diff --git a/library/cdr_generic.php b/library/cdr_generic.php index eebf910..53bf7de 100644 --- a/library/cdr_generic.php +++ b/library/cdr_generic.php @@ -1,3423 +1,3356 @@ 'RadAcctId', 'callId' => 'AcctSessionId', 'username' => 'UserName', 'domain' => 'Realm', 'gateway' => 'NASIPAddress', 'duration' => 'AcctSessionTime', 'startTime' => 'AcctStartTime', 'stopTime' => 'AcctStopTime', 'inputTraffic' => 'AcctInputOctets', 'outputTraffic' => 'AcctOutputOctets', 'aNumber' => 'CallingStationId', 'cNumber' => 'CalledStationId', 'timestamp' => 'timestamp', 'BillingPartyId' => 'UserName', 'sipRPID' => 'SipRPID', 'ResellerId' => 'BillingId', 'price' => 'Price', 'DestinationId' => 'DestinationId' ); function _readCDRNormalizationFieldsFromDB() { foreach (array_keys($this->CDRNormalizationFields) as $field) { $mysqlField = $this->CDRNormalizationFields[$field]; $CDRStructure[$mysqlField] = $this->CDRdb->f($mysqlField); } return $CDRStructure; } function _readCDRFieldsFromDB($fields) { foreach (array_keys($this->CDRFields) as $field) { $mysqlField = $this->CDRFields[$field]; $CDRStructure[$mysqlField] = $this->CDRdb->f($mysqlField); } return $CDRStructure; } function initCDRFields() { // init names of CDR fields foreach (array_keys($this->CDRFields) as $field) { $mysqlField = $this->CDRFields[$field]; $_field = $field."Field"; $this->$_field = $mysqlField; } } function initDatabaseConnection() { // connect to the CDR database(s) if(!$this->DATASOURCES[$this->cdr_source]['db_class']) { $log = sprintf("Error: \$DATASOURCES['%s']['db_class'] is not defined (init)", $this->cdr_source); syslog(LOG_NOTICE, $log); return 0; } $_dbClass = $this->DATASOURCES[$this->cdr_source]['db_class']; if (is_array($_dbClass)) { if ($_dbClass[0]) $this->primary_database = $_dbClass[0]; if ($_dbClass[1]) $this->secondary_database = $_dbClass[1]; } else { $this->primary_database = $_dbClass; } if(!class_exists($this->primary_database)) { $log = sprintf("Error: database class '%s' is not defined", $this->primary_database); syslog(LOG_NOTICE, $log); return 0; } $this->CDRdb = new $this->primary_database; // check db connectivity if (!$this->CDRdb->query('SELECT 1')) { $log = sprintf("Error: failed to connect to the primary CDR database %s\n", $this->primary_database); syslog(LOG_NOTICE, $log); if ($this->secondary_database) { $this->CDRdb = new $this->secondary_database; if (!$this->CDRdb->query('SELECT 1')) { $log = sprintf("Error: failed to connect to the secondary CDR database %s\n", $this->secondary_database); syslog(LOG_NOTICE, $log); return 0; } else { $this->CDRdb1 = new $this->secondary_database; $this->db_class = $this->secondary_database; } } else { return 0; } } else { $this->CDRdb1 = new $this->primary_database; $this->db_class = $this->primary_database; } return 1; } function CDRS($cdr_source) { global $CDRTool; global $DATASOURCES; global $RatingEngine; if (!$cdr_source) { $log = "Error: cdr_source not defined\n"; syslog(LOG_NOTICE, $log); return 0; } if (!$DATASOURCES[$cdr_source]) { $log = sprintf("Error: no such datasource defined (%s)\n", $cdr_source); syslog(LOG_NOTICE, $log); return 0; } $this->initDefaults(); $this->cdrtool = new DB_CDRTool(); $this->cdr_source = $cdr_source; $this->CDRTool = $CDRTool; $this->rating_settings = $RatingEngine; $this->DATASOURCES = $DATASOURCES; $this->cdrtool->Halt_On_Error = "no"; $this->table = $this->DATASOURCES[$this->cdr_source]['table']; - #TODO remove me, I am used to temporary sync mysql data with mongo data - if ($DATASOURCES[$cdr_source]['mongo_db']) { - $mongo_db = $this->CDRTool['mongo_db'][$DATASOURCES[$this->cdr_source]['mongo_db']]; - $mongo_uri = $mongo_db['uri']; - $mongo_replicaSet = $mongo_db['replicaSet']; - $mongo_database = $mongo_db['database']; - try { - $mongo_connection = new Mongo("mongodb://$mongo_uri", array("replicaSet" => $mongo_replicaSet)); - $db = $mongo_connection->selectDB($mongo_database); - $this->mongo_table = $db->selectCollection($this->table); - } catch (Exception $e) { - printf("

Caught exception in initDatabaseConnection(): %s", $e->getMessage()); - return 0; - } - } else { - $this->mongo_table = NULL; - } - $this->initCDRFields(); if ($this->DATASOURCES[$this->cdr_source]['rating']) { $this->ratingEnabled = 1; $this->rating = $this->DATASOURCES[$this->cdr_source]['rating']; if ($this->DATASOURCES[$this->cdr_source]['showRate']) $this->showRate = $this->DATASOURCES[$this->cdr_source]['showRate']; if ($this->DATASOURCES[$this->cdr_source]['rateField']) $this->rateField = $this->DATASOURCES[$this->cdr_source]['rateField']; if ($this->DATASOURCES[$this->cdr_source]['priceField']) $this->priceField = $this->DATASOURCES[$this->cdr_source]['priceField']; } if ($this->DATASOURCES[$this->cdr_source]['UserQuotaClass']) { $this->quotaEnabled = 1; $this->quota_init_flag = $this->cdr_source.':quotaCheckInit'; $this->quota_reset_flag = $this->cdr_source.':reset_quota_for'; if ($this->DATASOURCES[$this->cdr_source]['daily_quota']) { $this->daily_quota=$this->DATASOURCES[$this->cdr_source]['daily_quota']; } } $this->initDatabaseConnection(); if ($this->DATASOURCES[$this->cdr_source]['DestinationIdField']) { $this->DestinationIdField = $this->DATASOURCES[$this->cdr_source]['DestinationIdField']; } if ($this->DATASOURCES[$this->cdr_source]['normalizedField']) { $this->normalizedField = $this->DATASOURCES[$this->cdr_source]['normalizedField']; } if (strlen($this->DATASOURCES[$this->cdr_source]['intAccessCode'])) { $this->intAccessCode = $this->DATASOURCES[$this->cdr_source]['intAccessCode']; } if (strlen($this->DATASOURCES[$this->cdr_source]['natAccessCode'])) { $this->natAccessCode = $this->DATASOURCES[$this->cdr_source]['natAccessCode']; } if ($this->DATASOURCES[$this->cdr_source]['db_subscribers']) { if (class_exists($this->DATASOURCES[$this->cdr_source]['db_subscribers'])) { $this->AccountsDB = new $this->DATASOURCES[$this->cdr_source]['db_subscribers']; $this->db_subscribers = $this->DATASOURCES[$this->cdr_source]['db_subscribers']; } else { $log = sprintf( "Error: subscribers database class %s is not defined", $this->DATASOURCES[$this->cdr_source]['db_subscribers'] ); syslog(LOG_NOTICE, $log); return 0; } } else if (class_exists('DB_opensips')) { $this->AccountsDB = new DB_opensips(); $this->db_subscribers = 'DB_opensips'; } else { $log = sprintf( "Error: subscribers database is not defined, please define 'db_subscribers' in datasource '%s'", $this->cdr_source ); syslog(LOG_NOTICE, $log); return 0; } if ($this->DATASOURCES[$this->cdr_source]['BillingIdField']) { $this->BillingIdField = $this->DATASOURCES[$this->cdr_source]['BillingIdField']; } if ($this->DATASOURCES[$this->cdr_source]['E164_class']) { if (class_exists($this->DATASOURCES[$this->cdr_source]['E164_class'])) { $this->E164_class = $this->DATASOURCES[$this->cdr_source]['E164_class']; } else { printf( "Error: E164 class '%s' defined in datasource %s does not exist, using default '%s'", $this->DATASOURCES[$this->cdr_source]['E164_class'], $this->cdr_source, $this->E164_class ); } } if ($this->DATASOURCES[$this->cdr_source]['sipTrace']) { $this->sipTrace = $this->DATASOURCES[$this->cdr_source]['sipTrace']; } if ($this->DATASOURCES[$this->cdr_source]['mediaTrace']) { $this->mediaTrace = $this->DATASOURCES[$this->cdr_source]['mediaTrace']; } if ($this->DATASOURCES[$this->cdr_source]['domain_table']) { $this->domain_table = $this->DATASOURCES[$this->cdr_source]['domain_table']; } if ($this->DATASOURCES[$this->cdr_source]['skipNormalize']) { $this->skipNormalize = $this->DATASOURCES[$this->cdr_source]['skipNormalize']; } if ($this->DATASOURCES[$this->cdr_source]['enableThor']) { $this->enableThor = $this->DATASOURCES[$this->cdr_source]['enableThor']; } if (is_array($this->CDRTool['normalize']['CS_CODES'])) $this->CS_CODES=array_keys($this->CDRTool['normalize']['CS_CODES']); $this->missed_calls = $this->DATASOURCES[$this->cdr_source]['missed_calls']; $this->traceInURL = $this->DATASOURCES[$this->cdr_source]['traceInURL']; $this->traceOutURL = $this->DATASOURCES[$this->cdr_source]['traceOutURL']; $this->protocolTraceURL = $this->DATASOURCES[$this->cdr_source]['protocolTraceURL']; $spath = explode("/",$_SERVER["PHP_SELF"]); $last = count($spath)-1; $this->scriptFile=$spath[$last]; $this->next = $_REQUEST["next"]; $this->export = $_REQUEST["export"]; $this->trace = $_REQUEST["trace"]; if ($this->export) { $this->maxrowsperpage=10000000; } else { if ($_REQUEST["maxrowsperpage"]) { $this->maxrowsperpage = $_REQUEST["maxrowsperpage"]; } else { $this->maxrowsperpage = "25"; } } $this->LoadDisconnectCodes(); $this->LoadDestinations(); $this->LoadENUMtlds(); $this->LoadDomains(); $this->LoadTrustedPeers(); $this->getCDRtables(); if ($this->DATASOURCES[$this->cdr_source]['csv_writer_class']) { $csv_writter_class=$this->DATASOURCES[$this->cdr_source]['csv_writer_class']; if (class_exists($csv_writter_class)) { $this->csv_writter = new $csv_writter_class( $this->cdr_source, $this->DATASOURCES[$this->cdr_source]['csv_directory'], $this->db_subscribers ); } } $this->initOK=1; } function initDefaults() { if (is_readable('/etc/default/cdrtool')) { $defaultContentLines = explode("\n", file_get_contents('/etc/default/cdrtool')); foreach ($defaultContentLines as $_line) { list($defaults_key, $defaults_value) = explode("=", $_line); if (strlen($defaults_value)) $this->defaults[trim($defaults_key)]=trim($defaults_value); } } } function LoadDomains() { } function LoadTrustedPeers() { } function LoadAccounts() { } function LoadDestinations() { $_destinations = array(); $_destinations_sip = array(); $this->destinations_count = 0; $this->destinations_sip_count = 0; $query = sprintf("select `value` from memcache where `key` = 'destinations'"); if (!$this->cdrtool->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->cdrtool->Error, $this->cdrtool->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->cdrtool->num_rows()) { $b = time(); $this->cdrtool->next_record(); $_destinations = json_decode($this->cdrtool->f('value'),true); foreach (array_keys($_destinations) as $_key1) { foreach(array_keys($_destinations[$_key1]) as $_key2) { $this->destinations_count = $this->destinations_count + count($_destinations[$_key1][$_key2]); } } if (!$this->destinations_count) { $log = "Error: cached destinations key contains no data"; syslog(LOG_NOTICE, $log); } $query = sprintf("select `value` from memcache where `key` = 'destinations_sip'"); if (!$this->cdrtool->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->cdrtool->Error, $this->cdrtool->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->cdrtool->num_rows()) { $this->cdrtool->next_record(); $_destinations_sip = json_decode($this->cdrtool->f('value'), true); foreach (array_keys($_destinations_sip) as $_key1) { foreach (array_keys($_destinations_sip[$_key1]) as $_key2) { $this->destinations_sip_count = $this->destinations_count + count($_destinations_sip[$_key1][$_key2]); } } } /* $e=time(); $log=sprintf("Read %d PSTN destinations from cache in %d seconds",$this->destinations_count,$e-$b); syslog(LOG_NOTICE,$log); if ($this->destinations_sip_count) { $e=time(); $log=sprintf("Read %d SIP destinations from cache in %d seconds",$this->destinations_sip_count,$e-$b); syslog(LOG_NOTICE,$log); } */ $this->destinations = $_destinations; $this->destinations_sip = $_destinations_sip; unset($_destinations); unset($_destinations_sip); } else { $this->CacheDestinations(); $this->destinations = $this->_destinations; $this->destinations_sip = $this->_destinations_sip; unset($this->_destinations); unset($this->_destinations_sip); } if (is_array($this->destinations)) { foreach (array_keys($this->destinations) as $_reseller) { foreach ($this->destinations[$_reseller] as $key => $val) { $this->destinations_length[$_reseller][$key] = max(array_map(strlen, array_keys($val))); } } } $c = $this->destinations_count + $this->destinations_sip_count; return $c; } function CacheDestinations() { $this->_destinations = array(); $this->_destinations_sip = array(); $this->destinations_count = 0; $this->destinations_sip_count = 0; $b=time(); $query = "select * from destinations"; if ($this->CDRTool['filter']['aNumber']) { $faNumber=$this->CDRTool['filter']['aNumber']; $query .= sprintf(" where subscriber = '%s' or (subscriber = '' and domain = '' and gateway = '') ", addslashes($faNumber)); } else if ($this->CDRTool['filter']['domain']) { $fdomain=$this->CDRTool['filter']['domain']; $query .= sprintf(" where domain = '%s' or (subscriber = '' and domain = '' and gateway = '') ", addslashes($fdomain)); } else if ($this->CDRTool['filter']['gateway']) { $fgateway=$this->CDRTool['filter']['gateway']; $query .= sprintf(" where gateway = '%s' or (subscriber = '' and domain = '' and gateway = '') ",addslashes($fgateway)); } $this->cdrtool->query($query); if (!$this->cdrtool->num_rows()) { $log = "Error: could not find any entries in the destinations table"; syslog(LOG_NOTICE, $log); return 0; } $destinations_cache = "\n"; $destinations_sip_cache = "\n"; $this->destinations_count = 0; $this->destinations_default_count = 0; $this->destinations_gateway_count = 0; $this->destinations_domain_count = 0; $this->destinations_subscriber_count = 0; $j=0; while ($this->cdrtool->next_record()) { $j++; $reseller_id = $this->cdrtool->Record['reseller_id']; $gateway = trim($this->cdrtool->Record['gateway']); $domain = trim($this->cdrtool->Record['domain']); $subscriber = trim($this->cdrtool->Record['subscriber']); $dest_id = trim($this->cdrtool->Record['dest_id']); $region = utf8_encode($this->cdrtool->Record['region']); $name = utf8_encode($this->cdrtool->Record['dest_name']); $name_print = $this->cdrtool->Record['dest_name']." (".$dest_id.")"; if (strstr($dest_id, '@')) { // SIP destination if ($subscriber) { $this->_destinations_sip[$reseller_id][$subscriber][$dest_id] = array( 'name' => $name, 'region' => $region ); $this->destinations_sip_count++; } elseif ($domain) { $this->_destinations_sip[$reseller_id][$domain][$dest_id] = array( 'name' => $name, 'region' => $region ); $this->destinations_sip_count++; } elseif ($gateway) { $this->_destinations_sip[$reseller_id][$gateway][$dest_id] = array( 'name' => $name, 'region' => $region ); $this->destinations_sip_count++; } elseif ($dest_id) { $this->_destinations_sip[$reseller_id]["default"][$dest_id] = array( 'name' => $name, 'region' => $region ); $this->destinations_sip_count++; } } else { // PSTN destination if (!is_numeric($dest_id)) { $log = sprintf( "Error: cannot load non-numeric destination '%s' from row id %d" ,$dest_id ,$this->cdrtool->Record['id'] ); syslog(LOG_NOTICE, $log); continue; } if ($subscriber) { $this->destinations_subscriber_count++; $this->_destinations[$reseller_id][$subscriber][$dest_id]=array( 'name' => $name, 'region' => $region ); $this->destinations_count++; } elseif ($domain) { $this->destinations_domain_count++; $this->_destinations[$reseller_id][$domain][$dest_id]=array( 'name' => $name, 'region' => $region ); $this->destinations_count++; } elseif ($gateway) { $this->destinations_gateway_count++; $this->_destinations[$reseller_id][$gateway][$dest_id]=array( 'name' => $name, 'region'=> $region ); $this->destinations_count++; } elseif ($dest_id) { $this->destinations_default_count++; $this->_destinations[$reseller_id]["default"][$dest_id]=array( 'name' => $name, 'region' => $region ); $this->destinations_count++; } } } $destinations_cache = json_encode($this->_destinations); $destinations_sip_cache = json_encode($this->_destinations_sip); $log = sprintf("PSTN destinations cache size: %0.2f MB", strlen($destinations_cache) / 1024 / 1024); syslog(LOG_NOTICE, $log); if ($destinations_sip_cache) { $log = sprintf("SIP destinations cache size: %0.2f MB", strlen($destinations_sip_cache) / 1024 / 1024); syslog(LOG_NOTICE, $log); } $query = sprintf("select `value` from memcache where `key` = 'destinations'"); if (!$this->cdrtool->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->cdrtool->Error, $this->cdrtool->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->cdrtool->num_rows()) { $query = sprintf( "update memcache set value = '%s' where `key` = 'destinations'", addslashes($destinations_cache) ); if (!$this->cdrtool->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->cdrtool->Error, $this->cdrtool->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $log = sprintf( "Cached %d total, %d default, %d gateway, %d domain, %d subscriber destinations", $this->destinations_count, $this->destinations_default_count, $this->destinations_gateway_count, $this->destinations_domain_count, $this->destinations_subscriber_count ); syslog(LOG_NOTICE, $log); } else { $query = sprintf( "insert into memcache (`key`,`value`) values ('destinations','%s')", addslashes($destinations_cache) ); if (!$this->cdrtool->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->cdrtool->Error, $this->cdrtool->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $log = sprintf( "Cached %d total, %d default, %d gateway, %d domain, %d subscriber destinations", $this->destinations_count, $this->destinations_default_count, $this->destinations_gateway_count, $this->destinations_domain_count, $this->destinations_subscriber_count ); syslog(LOG_NOTICE, $log); } $query = sprintf("select `value` from memcache where `key` = 'destinations_sip'"); if (!$this->cdrtool->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->cdrtool->Error, $this->cdrtool->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->cdrtool->num_rows()) { $query = sprintf( "update memcache set value = '%s' where `key` = 'destinations_sip'", addslashes($destinations_sip_cache) ); if (!$this->cdrtool->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->cdrtool->Error, $this->cdrtool->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $log = sprintf("Cached %d SIP destinations", $this->destinations_sip_count); syslog(LOG_NOTICE, $log); } else { $query = sprintf( "insert into memcache (`key`,`value`) values ('destinations_sip','%s')", addslashes($destinations_sip_cache) ); if (!$this->cdrtool->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->cdrtool->Error, $this->cdrtool->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $log = sprintf("Updated cache for %d SIP destinations", $this->destinations_sip_count); syslog(LOG_NOTICE, $log); } return true; } function LoadENUMtlds() { $_ENUMtlds = array(); $query = "select * from billing_enum_tlds"; $this->cdrtool->query($query); while ($this->cdrtool->next_record()) { $_ENUMtlds[trim($this->cdrtool->Record['enum_tld'])] = array( 'discount' => trim($this->cdrtool->Record['discount']), 'e164_regexp' => trim($this->cdrtool->Record['e164_regexp']) ); } $this->ENUMtlds = $_ENUMtlds; $c = count($this->ENUMtlds); return count($this->ENUMtlds); } function LoadDisconnectCodes() { } function initForm() { } function searchForm() { } function showTableHeader() { } function showTableHeaderStatistics() { } function showResultsMenu($hide_rows = "", $begin_datetime = '', $end_datetime = '') { global $loginname; if (!$this->export) { print "

"; print "
url_edit\" > Refine searchurl_run\"> Refresh"; $log_query = sprintf( "insert into log (date,login,ip,url,results,rerun,reedit,datasource,reseller_id) values (NOW(),'%s','%s','%s','%s','%s','%s','%s',%d)", addslashes($loginname), addslashes($_SERVER["REMOTE_ADDR"]), addslashes($this->url), addslashes($this->rows), addslashes($this->url_run), addslashes($this->url_edit), addslashes($this->cdr_source), addslashes($this->CDRTool['filter']['reseller']) ); if ($this->cdrtool->query($log_query)) { $this->cdrtool->query("select LAST_INSERT_ID() as lid"); $this->cdrtool->next_record(); $current_log=$this->cdrtool->f('lid'); } if ($this->rows) { print "url_export\" target=_new> Export results to file
"; } else { print "
"; } print "
"; if (!$hide_rows) { print "
"; if ($this->rows == 0) { print "No records found"; } else { print "$this->rows records found"; } if ($begin_datetime && $end_datetime) { printf(" between %s and %s", $begin_datetime, $end_datetime); } print "
"; } } } function showResultsMenuSubscriber($hide_rows = "", $begin_datetime = '', $end_datetime = '') { global $loginname; if (!$this->export) { print "
"; $log_query = sprintf( "insert into log (date,login,ip,url,results,rerun,reedit,datasource,reseller_id) values (NOW(),'%s','%s','%s','%s','%s','%s','%s',%d)", addslashes($loginname), addslashes($_SERVER["REMOTE_ADDR"]), addslashes($this->url), addslashes($this->rows), addslashes($this->url_run), addslashes($this->url_edit), addslashes($this->cdr_source), 0 ); if ($this->cdrtool->query($log_query)) { $this->cdrtool->query("select LAST_INSERT_ID() as lid"); $this->cdrtool->next_record(); $current_log=$this->cdrtool->f('lid'); } if (!$this->CDRTool['filter']['aNumber']) { if ($this->rows) { print " | url_export\" target=_new>Export results to file"; } print " "; } print "
url_edit\">Refine search | url_run\">Refresh | Save a description for this query:
"; if (!$hide_rows) { print "
"; if ($this->rows == 0) { print "No records found"; } else { print "$this->rows records found"; } if ($begin_datetime && $end_datetime) { printf(" between %s and %s",$begin_datetime,$end_datetime); } print "
"; } } } function showDateTimeElements($f) { print " Start Time
"; $f->show_element("begin_date",""); print "
"; print "Time: "; print "
"; $f->show_element("begin_time",""); print "
Stop Time
"; $f->show_element("end_date",""); print "
"; print "Time: "; print "
"; $f->show_element("end_time",""); print "
"; } function showDataSources($f) { global $perm; print " Data Source "; $f->show_element("cdr_source",""); if (count($this->tables) > 0) { print " Table: "; $this->f->show_element("cdr_table",""); } print " "; } function showPagination($next, $maxrows) { $PHP_SELF = $_SERVER["PHP_SELF"]; if (!$this->export) { print " "; } } function show() { } function dump() { } function unNormalize($where = "", $table) { if ($this->skipNormalize) { return 0; } if (!$this->normalizedField) { return 0; } // do not allow renormalization for readonly accounts global $perm; if (is_object($perm) && $perm->have_perm('readonly')) return false; if (!$where) $where=" (1=1) "; if (!$table) $table=$this->table; $query=sprintf( "update %s set %s = '0' where %s ", addslashes($table), addslashes($this->normalizedField), $where ); $c=0; if ($this->CDRdb->query($query)) { $c = $this->CDRdb->affected_rows(); $this->reNormalize = true; } return $c; } function buildWhereForUnnormalizedSessions() { $this->whereUnnormalized = sprintf(" %s = '0'",$this->normalizedField); if ($this->stopTimeField) $this->whereUnnormalized .= " and $this->stopTimeField not like '0000-00-00 00:00:00%' "; if ($this->CDRFields['MediaTimeout']) { /* If we use MediaProxy information then eliminate all possible raise conditions 1. Session started and is in progress: AcctStopTime = '0000-00-00 00:00:00' AcctSessionTime = 0 MediaInfo is NULL ConnectInfo_stop is NULL 2. Session closed with a negative response code ([4-6]XX): AcctSessionTime = 0 AcctStopTime != '0000-00-00 00:00:00' MediaInfo is NULL ConnectInfo_stop is NULL 3. Session received a BYE: ConnectInfo_stop is not NULL AcctStopTime != '0000-00-00 00:00:00' 4. Media has timed-out: MediaInfo = 'timeout' ConnectInfo_stop is NULL AcctStopTime != '0000-00-00 00:00:00' 5. MediaProxy update before BYE is received: MediaInfo = '' ConnectInfo_stop is NULL AcctStopTime != '0000-00-00 00:00:00' 6. Mofified 5. for the case where the session received a broken BYE that did not generate a STOP while MediaProxy generated an UPDATE */ $this->whereUnnormalized .= " and (ConnectInfo_stop is not NULL or MediaInfo is NULL or MediaInfo != '' or (UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(AcctStopTime) > 20)) "; } } function getUnNormalized($where = "", $table) { if ($this->skipNormalize) { return 0; } if (!$where) $where=" (1=1) "; if (!$table) $table=$this->table; $ReNormalize = $_REQUEST["ReNormalize"]; if ($ReNormalize) $this->unNormalize($where, $table); if (!$this->normalizedField) { return 0; } $this->buildWhereForUnnormalizedSessions(); $query=sprintf( "select count(*) as c from %s where %s and %s", addslashes($table), $where, $this->whereUnnormalized ); if ($this->CDRdb->query($query)) { $this->CDRdb->next_record(); $c = $this->CDRdb->f('c'); } return $c; } function NormalizeCDRS($where = "", $table = "") { $this->missing_destinations=array(); $b=time(); if (!$where) $where=" (1=1) "; if (!$table) $table=$this->table; if ($this->skipNormalize) { return 1; } if (!$this->normalizedField) { return 1; } $lockName = sprintf("%s:%s", $this->cdr_source, $table); if (!$this->getNormalizeLock($lockName)) { //printf("Cannot get obtain lock %s",$lockName); return true; } $this->buildWhereForUnnormalizedSessions(); $this->status['cdr_to_normalize'] = 0; $this->status['normalized'] = 0; $this->status['normalize_failures'] = 0; $query = sprintf( "select count(*) as c from %s where %s and %s", addslashes($table), $where, $this->whereUnnormalized ); if ($this->CDRdb->query($query)) { $this->CDRdb->next_record(); $c=$this->CDRdb->f('c'); } $this->status['cdr_to_normalize']=$c; //$this->status['cdr_to_normalize']=$this->CDRdb->num_rows(); //print "

$query"; if ($this->status['cdr_to_normalize'] > 0) { if ($this->ratingEnabled) { // Load rating tables $this->RatingTables = new RatingTables(); $this->RatingTables->LoadRatingTables(); } } else { return 0; } $this->usageKeysForDeletionFromCache = array(); // For loop to process 1k records each time for ($i = 0; $i <= $this->status['cdr_to_normalize']; $i=$i+1000) { $query = sprintf( "select *, UNIX_TIMESTAMP($this->startTimeField) as timestamp from %s where %s and %s limit 0,1000", addslashes($table), $where, $this->whereUnnormalized ); if (!$this->CDRdb->query($query)) { $log = sprintf( "Database error: %s (%s)\n", $this->CDRdb->Error, $this->CDRdb->Errno ); syslog(LOG_NOTICE, $log); print $log; return false; } while ($this->CDRdb->next_record()) { //$Structure=$this->_readCDRNormalizationFieldsFromDB(); $Structure=$this->_readCDRFieldsFromDB(''); if ($this->csv_writter) { if (!$this->csv_file_cannot_be_opened) { if (!$this->csv_writter->ready) { if (!$this->csv_writter->open_file($Structure[$this->CDRNormalizationFields['id']])) { $this->csv_file_cannot_be_opened = true; } else { $this->csv_file_ready = true; } } } } $found++; $CDR = new $this->CDR_class($this, $Structure); if ($CDR->normalize("Save", $table)) { $this->status['normalized']++; if ($this->csv_file_ready) { if (!$this->csv_writter->write_cdr($CDR)) { // stop writing future records if we have a failure $this->csv_file_cannot_be_opened = true; } } if ($CDR->broken_rate) { $this->brokenRates[$CDR->DestinationId]++; } } else { $this->status['normalize_failures']++; } if ($this->reNormalize && !$this->usageKeysForDeletionFromCache[$CDR->BillingPartyId]) { $this->usageKeysForDeletionFromCache[$CDR->BillingPartyId]++; } if ($this->status['cdr_to_normalize'] > 1000) { if ($found > $progress*$this->status['cdr_to_normalize']/100) { $progress++; if ($progress%10==0) { print "$progress% "; flush(); } } } } } if ($this->ratingEnabled && count($this->brokenRates) > 0) { if ($this->rating_settings['reportMissingRates']) { if (count($this->brokenRates)) { foreach (array_keys($this->brokenRates) as $dest) { $missingRatesBodytext=$missingRatesBodytext."\nDestination id $dest (".$this->brokenRates[$dest]." calls)"; } $to = $this->CDRTool['provider']['toEmail']; $from = $this->CDRTool['provider']['fromEmail']; $log = sprintf( "Mailing missing rates for %d destination(s) to %s", count($this->brokenRates), $to ); syslog(LOG_NOTICE, $log); mail($to, "Missing CDRTool rates",$missingRatesBodytext, "From: $from"); } } } if (count($this->missing_destinations)) { $to = $this->CDRTool['provider']['toEmail']; $from = $this->CDRTool['provider']['fromEmail']; $body = ''; foreach ($this->missing_destinations as $_dest) { if (!$seen[$_dest]) { $body .= sprintf("No destination for number %s\n", $_dest); } $seen[$_dest]++; } mail($to, "Missing CDRTool destinations", $body, "From: $from"); } if ($this->status['cdr_to_normalize'] > 0) { $d = time() - $b; $log = sprintf("Normalization done in %d s, memory usage: %0.2f MB", $d, memory_get_usage() / 1024 / 1024); syslog(LOG_NOTICE, $log); } if ($this->csv_file_ready) { $this->csv_writter->close_file(); $this->csv_writter->ready = false; } if (count($this->usageKeysForDeletionFromCache)) { $this->resetQuota(array_keys($this->usageKeysForDeletionFromCache)); } return 1; } function NormalizeNumber($Number, $type = "destination", $subscriber = "", $domain = "", $gateway = "", $CountryCode = "", $ENUMtld = "", $reseller_id = 0) { $this->CSCODE=""; $Number = strtolower(quoted_printable_decode($Number)); if ($pos = strpos($Number, "@")) { // this is a SIP URI $NumberStack['username'] = substr($Number, 0, $pos); if (strlen($NumberStack['username']) < 1) { $NumberStack['username'] = "unknown"; } $NumberStack['domain'] = substr($Number,$pos+1); $NumberStack['delimiter'] = "@"; $pos = strpos($NumberStack['username'], ":"); if ($pos) { $NumberStack['protocol'] = substr($NumberStack['username'], 0, $pos+1); $NumberStack['username'] = substr($NumberStack['username'], $pos+1); } if (preg_match("/^(.*)[=:;]/U", $NumberStack['domain'], $p)){ $NumberStack['domain'] = $p[1]; } } else if (preg_match("/^([a-z0-9]+:)(.*)$/i", $Number, $m)) { #$oct=preg_split("/\./",$m[2]); $oct = explode(",", $m[2]); if(sizeof($oct) == 4) { // This is a SIP address without username $NumberStack['username'] = ""; $NumberStack['domain'] = $m[2]; } else { // This is a SIP address without domain $NumberStack['username'] = $m[2]; $NumberStack['domain'] = ""; } $NumberStack['protocol'] = $m[1]; $NumberStack['delimiter'] = ""; } else { // This is a simple address like a phone number $NumberStack['protocol'] = ""; $NumberStack['username'] = $Number; $NumberStack['delimiter'] = ""; $NumberStack['domain'] = ""; } if (preg_match("/^(.*)[=:;]/U", $NumberStack['domain'], $p)){ $NumberStack['domain'] = $p[1]; } // Translate the domain if (is_array($this->DATASOURCES[$this->cdr_source]['domainTranslationDestination']) && isset($this->DATASOURCES[$this->cdr_source]['domainTranslationDestination'][$NumberStack['domain']]) ) { $NumberStack['domain'] = $this->DATASOURCES[$this->cdr_source]['domainTranslationDestination'][$NumberStack['domain']]; } if ($type=="destination" && is_numeric($NumberStack['username'])) { // strip custom prefix from destination $usernameLength = strlen($NumberStack['username']); if (is_array($this->CS_CODES)) { foreach ($this->CS_CODES as $strip_prefix) { $prefixLength = strlen($strip_prefix); $restLength = $usernameLength-$prefixLength; if ($restLength > 0 and preg_match("/^$strip_prefix(.*)$/", $NumberStack['username'], $m)) { $NumberStack['username'] = $m[1]; $this->CSCODE = $strip_prefix; break; } } } if (!$CountryCode) $CountryCode = $this->CDRTool['normalize']['defaultCountryCode']; $e164class = $this->E164_class; $E164 = new $e164class( $this->intAccessCode, $this->natAccessCode, $CountryCode, $this->ENUMtlds[$ENUMtld]['e164_regexp'] ); $NumberStack['E164'] = $E164->E164Format($NumberStack['username']); } if ($type=="destination" && $NumberStack['E164']) { // lookup destination id for the E164 number $dst_struct = $this->lookupDestination( $NumberStack['E164'], $subscriber, $domain, $gateway,$reseller_id ); $NumberStack['DestinationId'] = $dst_struct[0]; $NumberStack['destinationName'] = $dst_struct[1]; $NumberStack['NumberPrint'] = "+".$NumberStack['E164']; if (!$ENUMtld) { $NumberStack['Normalized'] = $this->intAccessCode. $NumberStack['E164']. $NumberStack['delimiter']. $NumberStack['domain']; } else { $NumberStack['Normalized'] = $NumberStack['username']. $NumberStack['delimiter']. $NumberStack['domain']; } } else { $dst_struct = $this->lookupDestination( $Number, $subscriber, $domain, $gateway, $reseller_id ); $NumberStack['DestinationId'] = $dst_struct[0]; $NumberStack['destinationName'] = $dst_struct[1]; $NumberStack['NumberPrint'] = $NumberStack['username']. $NumberStack['delimiter']. $NumberStack['domain']; $NumberStack['Normalized'] = $NumberStack['username']. $NumberStack['delimiter']. $NumberStack['domain']; } return $NumberStack; } function lookupDestination($destination, $subscriber = "", $domain = "", $gateway = "", $reseller_id = 0) { if (!$destination) return; if (is_numeric($destination)) { return $this->lookupPSTNDestination($destination, $subscriber, $domain, $gateway, $reseller_id); } else { return $this->lookupSipDestination($destination, $subscriber, $domain, $gateway, $reseller_id); } } function lookupSipDestination($destination = '', $subscriber = '', $domain = '', $gateway = '', $reseller_id = 0) { if ($this->destinations_sip[$reseller_id][$subscriber]) { $destinations_sip = $this->destinations_sip[$reseller_id][$subscriber]; $fCustomer = "subscriber=$subscriber"; } else if ($this->destinations_sip[$reseller_id][$domain]) { $destinations_sip = $this->destinations_sip[$reseller_id][$domain]; $fCustomer = "domain=$domain"; } else if ($this->destinations_sip[$reseller_id][$gateway]) { $destinations_sip = $this->destinations_sip[$reseller_id][$gateway]; $fCustomer = "gateway=$gateway"; } else if ($this->destinations_sip[$reseller_id]['default']) { $destinations_sip = $this->destinations_sip[$reseller_id]['default']; $fCustomer = "default"; } else if ($this->destinations_sip[0][$subscriber]) { $destinations_sip = $this->destinations_sip[0][$subscriber]; $fCustomer = "subscriber=$subscriber"; } else if ($this->destinations_sip[0][$domain]) { $destinations_sip = $this->destinations_sip[0][$domain]; $fCustomer = "domain=$domain"; } else if ($this->destinations_sip[0][$gateway]) { $destinations_sip = $this->destinations_sip[0][$gateway]; $fCustomer = "gateway=$gateway"; } else if ($this->destinations_sip[0]['default']) { $destinations_sip = $this->destinations_sip[0]['default']; $fCustomer = "default"; } $ret = false; if ($destinations_sip[$destination]) { $ret = array($destination,$destinations_sip[$destination]['name']); } else { list($user,$domain) = explode("@", $destination); if ($domain) { $domain = sprintf("@%s", $domain); if ($destinations_sip[$domain]) { $ret = array($domain, $destinations_sip[$domain]['name']); } } } return $ret; } function lookupPSTNDestination($destination = '', $subscriber = '', $domain = '',$gateway = '', $reseller_id = 0) { if ($this->destinations[$reseller_id][$subscriber]) { $_destinations = $this->destinations[$reseller_id][$subscriber]; $maxLength = $this->destinations_length[$reseller_id][$subscriber]; $fCustomer="subscriber=$subscriber"; } else if ($this->destinations[$reseller_id][$domain]) { $_destinations = $this->destinations[$reseller_id][$domain]; $maxLength = $this->destinations_length[$reseller_id][$domain]; $fCustomer="domain=$domain"; } else if ($this->destinations[$reseller_id][$gateway]) { $_destinations = $this->destinations[$reseller_id][$gateway]; $maxLength = $this->destinations_length[$reseller_id][$gateway]; $fCustomer="gateway=$gateway"; } else if ($this->destinations[$reseller_id]['default']) { $_destinations = $this->destinations[$reseller_id]['default']; $maxLength = $this->destinations_length[$reseller_id]['default']; $fCustomer="default"; } else if ($this->destinations[0][$subscriber]) { $_destinations = $this->destinations[0][$subscriber]; $maxLength = $this->destinations_length[0][$subscriber]; $fCustomer="subscriber=$subscriber"; } else if ($this->destinations[0][$domain]) { $_destinations = $this->destinations[0][$domain]; $maxLength = $this->destinations_length[0][$domain]; $fCustomer="domain=$domain"; } else if ($this->destinations[0][$gateway]) { $_destinations = $this->destinations[0][$gateway]; $maxLength = $this->destinations_length[0][$gateway]; $fCustomer="gateway=$gateway"; } else if ($this->destinations[0]['default']) { $_destinations = $this->destinations[0]['default']; $maxLength = $this->destinations_length[0]['default']; $fCustomer="default"; } else { $log = sprintf( "Error: cannot find destinations for subscriber='%s', domain ='%s', gateway='%s', reseller='%s'\n", $subscriber, $domain, $gateway, $reseller_id ); syslog(LOG_NOTICE, $log); } if (count($_destinations) > 0) { $length = min(strlen($destination), $maxLength); for ($i = $length; $i > 0; $i--) { $buf = substr($destination, 0, $i); if ($_destinations[$buf]) { return array($buf, $_destinations[$buf]['name']); } } } $log = sprintf( "Error: cannot find destination id for %s of customer = '%s', total destinations = %d\n", $destination, $fCustomer, count($_destinations) ); syslog(LOG_NOTICE, $log); $this->missing_destinations[] = $destination; return false; } function import($file) { } function RadiusRecordRead($fp) { $keepreading=1; while ($keepreading) { $contents = fgets($fp, 8192); if (preg_match("/^$/", $contents)) { $keepreading=0; } else { $record[]=$contents; } } return $record; } function RadiusRecordParse($record) { unset($radiusParsed); if (!is_array($record)) { return 0; } foreach ($record as $line) { $line=trim($line); foreach (array_keys($this->radiusAttributes) as $attribute) { if (preg_match("/$attribute = (.*)$/", $line, $m)) { $value = preg_replace("/\"/", "", trim($m[1])); $radiusParsed[$attribute] = $value; } } } return $radiusParsed; } function getCDRtables() { if (!is_object($this->CDRdb)) return 0; $_tables=$this->CDRdb->table_names(); $t=count($_tables); if ($this->table) $this->tables[]=$this->table; while ($t <> 0) { $_table=$_tables[$t-1]["table_name"]; if ($_table=='radacct') $this->tables[]='radacct'; if (preg_match("/^(\w+)(\d{6})$/", $_table, $m)) { if ($list_t > 24) break; $this->tables[] = $_table; $list_t++; } $t--; } $this->tables=array_unique($this->tables); } function rotateTable($sourceTable, $month, $action) { // create a new table tableYYYYMM and copy data from the main table into it // if no month is supplied, the default is the previous month if (!$month) $month=date('Ym', mktime(0, 0, 0, date("m") - 1, "01", date("Y"))); if (!$sourceTable) $sourceTable = $this->table; if (preg_match("/^(\w+)\d{6}$/", $sourceTable, $m)) { $destinationTable = $m[1].$month; } else { $destinationTable = $sourceTable.$month; } print("rotateTable($sourceTable, $month, $destinationTable)\n"); if ($sourceTable == $destinationTable) { $log = sprintf("Error: cannot copy records to the same table %s.\n", $destinationTable); syslog(LOG_NOTICE, $log); print $log; return 0; } $createTableFile = $this->CDRTool['Path'].$this->createTableFile; if (!$this->createTableFile || !is_readable($createTableFile)) { $log = sprintf("Error: cannot locate mysql creation file\n"); syslog(LOG_NOTICE, $log); print $log; return 0; } $lockFile="/var/lock/CDRTool_".$this->cdr_source."_rotateTable.lock"; $f = fopen($lockFile, "w"); if (flock($f, LOCK_EX + LOCK_NB, $w)) { if ($w) { $log = sprintf("Another CDRTool rotate table is in progress. Aborting.\n"); syslog(LOG_NOTICE, $log); print $log; return 0; } } else { $log = sprintf("Another CDRTool rotate table is in progress. Aborting.\n"); syslog(LOG_NOTICE, $log); print $log; return 0; } $b=time(); if (!preg_match("/^(\d{4})(\d{2})$/", $month, $m)) { print "Error: Month $month must be in YYYYMM format\n"; return 0; } else { if ($m[2] > 12) { print "Error: Month must be in YYYYMM format\n"; return 0; } $lastMonth = $month; $startSQL = $m[1]."-".$m[2]."-01"; $stopSQL =date('Y-m-01', mktime(0, 0, 0, $m[2] + 1, "01", $m[1])); } $query = sprintf( "select count(*) as c from %s where %s >='%s' and %s < '%s'\n", addslashes($sourceTable), addslashes($this->CDRFields['startTime']), addslashes($startSQL), addslashes($this->CDRFields['startTime']), addslashes($stopSQL) ); if ($this->CDRdb->query($query)) { $this->CDRdb->next_record(); $rowsSourceTable = $this->CDRdb->f('c'); $log=sprintf("Source table %s has %d records in month %s\n", $sourceTable, $rowsSourceTable, $month); syslog(LOG_NOTICE, $log); print $log; if (!$rowsSourceTable) return 1; } else { $log = sprintf("Error: %s (%s)\n", $this->table, $this->CDRdb->Error); syslog(LOG_NOTICE, $log); print $log; return 0; } $query = sprintf("select count(*) as c from %s\n", addslashes($destinationTable)); if ($this->CDRdb->query($query)) { $this->CDRdb->next_record(); $rowsDestinationTable = $this->CDRdb->f('c'); $log = sprintf("Destination table %s has %d records\n", $destinationTable, $rowsDestinationTable); syslog(LOG_NOTICE, $log); print $log; if ($rowsDestinationTable != $rowsSourceTable) { $log = sprintf( "Error: source table has %d records and destination table has %d records\n", $rowsSourceTable, $rowsDestinationTable ); syslog(LOG_NOTICE, $log); print $log; } else { $log = sprintf("Tables are in sync\n"); syslog(LOG_NOTICE, $log); print $log; } } else { $log = sprintf("%s (%s)\n", $this->CDRdb->Error, $this->CDRdb->Errno); syslog(LOG_NOTICE, $log); print $log; if ($this->CDRdb->Errno==1146) { $destinationTableTmp = $destinationTable."_tmp"; $query=sprintf("drop table if exists %s", addslashes($destinationTableTmp)); print($query); $this->CDRdb->query($query); if ($query=file_get_contents($createTableFile)) { $query=preg_replace("/CREATE TABLE.*/", "CREATE TABLE $destinationTableTmp (", $query); if (!$this->CDRdb->query($query)) { $log = sprintf("Error creating table %s: %s, %s\n", $destinationTableTmp, $this->CDRdb->Error,$query); syslog(LOG_NOTICE, $log); print $log; return 0; } } else { $log = sprintf("Cannot read file %s\n",$createTableFile); syslog(LOG_NOTICE, $log); print $log; return 0; } // if we reached this point we start to copy records $query = sprintf( "insert into %s select * from %s where %s >='%s' and %s < '%s'", addslashes($destinationTableTmp), addslashes($sourceTable), addslashes($this->CDRFields['startTime']), addslashes($startSQL), addslashes($this->CDRFields['startTime']), addslashes($stopSQL) ); return; if ($this->CDRdb->query($query)) { $e=time(); $d=$e-$b; $rps=0; if ($this->CDRdb->affected_rows() && $d) $rps=$this->CDRdb->affected_rows()/$d; $log = printf("Copied %d CDRs into table %s in %d s @ %.0f rps\n",$this->CDRdb->affected_rows(),$destinationTableTmp,$d,$rps); syslog(LOG_NOTICE,$log); print $log; $query=sprinf("rename table %s to %s", addslashes($destinationTableTmp),addslashes($destinationTableTmp)); if (!$this->CDRdb->query($query)) { printf ("Error renaming table %s to %s: %s\n",$destinationTableTmp,$destinationTable,$this->CDRdb->Error); return 0; } } else { printf ("Error copying records in table %s: %s\n",$destinationTable,$this->CDRdb->Error); return 0; } } } } function purgeTable($sourceTable, $month) { // delete records for a given month with minimal locking of database // this function is useful after archive of CDR data using rotate script $begin=time(); if ($month) { if (!preg_match("/^(\d{4})(\d{2})$/",$month,$m)) { print "Error: Month must be in YYYYMM format\n"; return 0; } else { $beginDate=$m[1]."-".$m[2]."-01"; $endDate=date('Y-m-d', mktime(0, 0, 0, $m[2]+1, '01', $m[1])); } } else if (is_int($this->DATASOURCES[$this->cdr_source]['purgeCDRsAfter'])) { $beginDate="1970-01-01"; $endDate=date('Y-m-d', mktime(0, 0, 0, Date('m'), Date('d')-$this->DATASOURCES[$this->cdr_source]['purgeCDRsAfter'], Date('Y'))); } else { return 0; } if (!$sourceTable) $sourceTable=$this->table; $query = sprintf( "select min(%s) as min,max(%s) as max from %s where %s >= '%s' and %s < '%s' ", addslashes($this->CDRFields['id']), addslashes($this->CDRFields['id']), addslashes($sourceTable), addslashes($this->CDRFields['startTime']), addslashes($beginDate), addslashes($this->CDRFields['startTime']), addslashes($endDate) ); dprint($query); if (!$this->CDRdb->query($query)) { printf ("Error: %s",$this->CDRdb->Error); return 0; } $this->CDRdb->next_record(); $min=$this->CDRdb->f('min'); $max=$this->CDRdb->f('max'); if (!$min || !$max) { $log=sprintf("No CDRs found in %s between %s and %s\n",$sourceTable,$beginDate,$endDate); print $log; syslog(LOG_NOTICE,$log); return 0; } $deleted=0; $i=$min; $interval=100; $rows2delete=$max-$min; $found = 0; print "$rows2delete CDRs will be deleted between $min and $max, $interval at a time\n"; while ($i <= $max) { $found=$found+$interval; if ($i + $interval < $max) { $top=$i; } else { $top=$max; } $query=sprintf("delete low_priority from %s where %s <= '%d' and %s >= '%d'", addslashes($sourceTable), addslashes($this->CDRFields['id']), addslashes($top), addslashes($this->CDRFields['id']), addslashes($min) ); if ($this->CDRdb->query($query)) { $deleted=$deleted+$this->CDRdb->affected_rows(); } else { $log=sprintf("Error: %s (%s)",$this->CDRdb->Error,$this->CDRdb->Errno); syslog(LOG_NOTICE,$log); print $log; return 0; } if ($found > $progress*$rows2delete/100) { $progress++; if ($progress%10==0) { print "$progress% "; flush(); } } print "."; flush(); $i=$i+$interval; } print "\n"; $end = time(); $duration = $end-$begin; $rps=0; if ($deleted && $duration) $rps=$deleted/$duration; $log=sprintf("%s CDRs of month %s deleted from %s in %d s @ %.0f rps\n",$deleted,$month,$sourceTable,$duration,$rps); syslog(LOG_NOTICE,$log); print $log; return 1; } function cacheQuotaUsage($accounts=array()) { if (!$this->quotaEnabled) return true; $saved_keys=0; $failed_keys=0; foreach (array_keys($accounts) as $_key) { $query=sprintf("select id from quota_usage where datasource = '%s' and account = '%s'",addslashes($this->cdr_source),addslashes($_key)); if (!$this->cdrtool->query($query)){ $log=sprintf ("Database error: %s (%s)",$this->cdrtool->Error,$this->cdrtool->Errno); syslog(LOG_NOTICE, $log); print($log); return false; } if ($this->cdrtool->num_rows()) { // sync with quota_usage table $query=sprintf("update quota_usage set calls = calls + %d, duration = duration + %d, cost = cost + '%s', cost_today = cost_today + '%s', traffic = traffic + '%s' where account = '%s' ", addslashes($accounts[$_key]['usage']['calls']), addslashes($accounts[$_key]['usage']['duration']), addslashes($accounts[$_key]['usage']['cost']), addslashes($accounts[$_key]['usage']['cost_today']), addslashes($accounts[$_key]['usage']['traffic']), addslashes($_key) ); if (!$this->cdrtool->query($query)){ $log=sprintf ("Database error: %s (%s)",$this->cdrtool->Error,$this->cdrtool->Errno); syslog(LOG_NOTICE, $log); $failed_keys++; } else { $saved_keys++; } } else { $quota=$this->getQuota($_key); $blocked=$this->getBlockedByQuotaStatus($_key); list($_u,$_d)=explode("@",$_key); $query=sprintf("insert into quota_usage (datasource,account,domain,quota,calls,duration,cost,cost_today,traffic,blocked,reseller_id) values ('%s','%s','%s',%d,%d,'%s','%s','%s','%s','%s',%d) ", addslashes($this->cdr_source), addslashes($_key), addslashes($_d), addslashes($quota), addslashes($accounts[$_key]['usage']['calls']), addslashes($accounts[$_key]['usage']['duration']), addslashes($accounts[$_key]['usage']['cost']), addslashes($accounts[$_key]['usage']['cost_today']), addslashes($accounts[$_key]['usage']['traffic']), intval($blocked), addslashes($this->localDomains[$_d]['reseller']) ); if (!$this->cdrtool->query($query)){ $log=sprintf ("Database error: %s (%s)",$this->cdrtool->Error,$this->cdrtool->Errno); syslog(LOG_NOTICE, $log); $failed_keys++; } else { $saved_keys++; } } } $this->status['cached_keys']['saved_keys'] = $this->status['cached_keys']['saved_keys'] + $saved_keys; $this->status['cached_keys']['failed_keys'] = $this->status['cached_keys']['failed_keys'] + $failed_keys; return 1; } function getNormalizeLock($lockname='') { if (!$locker = new DB_Locker()) { $log=sprintf("Error: cannot init locker database. "); print $log; syslog(LOG_NOTICE, $log); return 0; } if (!$lockname) { $log=sprintf("Error: no lockname provided. "); print $log; syslog(LOG_NOTICE, $log); return 0; } unset($this->lock_connection_id); register_shutdown_function("unLockNormalization",$locker,$lockname); $query=sprintf("SELECT GET_LOCK('%s',0)",addslashes($lockname)); if ($locker->query($query)) { $locker->next_record(); $return = $locker->Record["GET_LOCK('$lockname',0)"]; $query=sprintf("SELECT IS_USED_LOCK('%s')",addslashes($lockname)); if ($locker->query($query)) { $locker->next_record(); $this->lock_connection_id=$locker->Record["IS_USED_LOCK('$lockname')"]; } if ($return == 0) { $log=sprintf("Lock %s already aquired by another process with id %s ",$lockname,$this->lock_connection_id); syslog(LOG_NOTICE, $log); print "$log\n"; return 0; } else { $log=sprintf("Normalize lock id %s aquired for %s ",$this->lock_connection_id,$lockname); syslog(LOG_NOTICE, $log); //print "$log\n"; return 1; } } else { $log=sprintf("Database error: failed to request mysql lock %s (%s)\n",$locker->Error,$locker->Errno); print $log; syslog(LOG_NOTICE, $log); return 0; } } function getQuota($account) { } function getBlockedByQuotaStatus($account) { } function resetQuota($accounts=array()) { if (!$this->quotaEnabled) return true; $_reset_array=array_unique($accounts); foreach ($_reset_array as $_el) { if (strlen($_el)) $_accounts[]=$_el; } $_reset_array=$_accounts; $log=sprintf("Next quota check will rebuild the counters for %s accounts",count($_reset_array)); syslog(LOG_NOTICE,$log ); $query=sprintf("delete from memcache where `key` in ('%s','%s')",addslashes($this->quota_init_flag),addslashes($this->quota_reset_flag)); if (!$this->cdrtool->query($query)) { $log=sprintf ("Database error for query %s: %s (%s)",$query,$this->cdrtool->Error,$this->cdrtool->Errno); print $log; syslog(LOG_NOTICE, $log); return false; } $query=sprintf("insert into memcache (`key`,`value`) values ('%s','%s')",addslashes($this->quota_reset_flag),addslashes(json_encode($_reset_array))); if (!$this->cdrtool->query($query)) { $log=sprintf ("Database error for query %s: %s (%s)",$query,$this->cdrtool->Error,$this->cdrtool->Errno); print $log; syslog(LOG_NOTICE, $log); return false; } $query="delete from quota_usage where account in ("; $t=0; foreach ($_reset_array as $_el) { if ($t) $query.=","; $query.= sprintf("'%s'",addslashes($_el)); $t++; } $query.=")"; if (!$this->cdrtool->query($query)) { $log=sprintf ("Database error: %s (%s)",$this->cdrtool->Error,$this->cdrtool->Errno); syslog(LOG_NOTICE,$log); print $log; return 0; } else { return 1; } } } class CDRS_unknown extends CDRS { function searchForm() { return; } } class E164 { // Class that helps normalization of a telephone number in E164 format // Based on this normalization, CDRTool rating engine decides whether // to consider the session a PSTN destination and rate it according // to the PSTN rating plan function E164($intAccessCode='00', $natAccessCode='0',$CountryCode='',$ENUMtldRegexp="") { $this->regexp_international = "/^".$intAccessCode."([0-9]{5,})\$/"; $this->regexp_national = "/^".$natAccessCode."([0-9]{3,})\$/"; $this->CountryCode = trim($CountryCode); $this->ENUMtldRegexp = trim($ENUMtldRegexp); } function E164Format($Number) { //dprint "E164Format($Number,ENUMtldRegexp=$this->ENUMtldRegexp)"; // This function returns the full E164 format for a PSTN number without leading zero or + // E164 = Country Code + Network Code + Subscriber Number // Example: 31208015100 is an E164 number from Holland (country code 31) // If nothing is returned by this function the session is considered an Internet destination if (preg_match($this->regexp_international,$Number,$m)) { return $m[1]; } else if (preg_match($this->regexp_national,$Number,$m)) { // Add default country code return $this->CountryCode.$m[1]; } else if (strlen($this->ENUMtldRegexp)) { $_regexp="/^".$this->ENUMtldRegexp."\$/"; if (preg_match($_regexp,$Number,$m)) { return $m[1]; } } return false; } } class E164_Europe extends E164 { function E164_Europe ($intAccessCode='00', $natAccessCode='0',$CountryCode='',$ENUMtldRegexp="([1-9][0-9]{7,})") { $this->regexp_international = "/^".$intAccessCode."([1-9][0-9]{5,})\$/"; $this->regexp_national = "/^".$natAccessCode."([1-9][0-9]{3,})\$/"; $this->CountryCode = trim($CountryCode); $this->ENUMtldRegexp = trim($ENUMtldRegexp); } } class E164_US extends E164 { function E164_US($intAccessCode='011', $natAccessCode='[1-9][0-9]{2}',$CountryCode='',$ENUMtldRegexp="([1-9][0-9]{7,})") { $this->regexp_international = "/^".$intAccessCode."([1-9][0-9]{5,})\$/"; $this->regexp_national = "/^".$natAccessCode."([0-9]{3,})\$/"; $this->CountryCode = trim($CountryCode); $this->ENUMtldRegexp = trim($ENUMtldRegexp); } } class CDR { // we need two db descriptors to update a CDR // within same result set var $idField = "RadAcctId"; var $callIdField = "AcctSessionId"; var $usernameField = "UserName"; var $domainField = "Realm"; var $gatewayField = "NASIPAddress"; var $gatewayPortField = "CiscoNASPort"; var $timestampField = "timestamp"; var $portIdField = "NASPortId"; var $portTypeField = "NASPortType"; var $startTimeField = "AcctStartTime"; var $stopTimeField = "AcctStopTime"; var $durationField = "AcctSessionTime"; var $inputTrafficField = "AcctInputOctets"; var $outputTrafficField = "AcctOutputOctets"; var $serviceTypeField = "ServiceType"; var $cNumberField = "CalledStationId"; var $aNumberField = "CallingStationId"; var $disconnectField = "H323DisconnectCause"; var $traceIn = ""; var $traceOut = ""; var $defaultApplicationType = "audio"; var $supportedApplicationTypes = array('audio', 'message', 'video', 'chat', 'file-transfer' ); function CDR() { } function NormalizeDisconnect() { $causePrint=$this->CDRS->disconnectCodesDescription[$this->disconnect]." (".$this->disconnect.")"; return $causePrint; } function traceOut () { } function traceIn () { } function show() { } function normalize($save="",$table="") { if (!$table) $table = $this->CDRS->table; if ($this->CDRS->CSCODE && $CarrierInfo = $this->CDRS->CDRTool['normalize']['CS_CODES'][$this->CDRS->CSCODE]) { // We found a carrier so we set the BillingId $this->BillingId = $CarrierInfo[BillingPartyId]; } if ($save) { if (!$this->id) { return 0; } $query =""; $query1 =""; $query2 =""; if ($this->CDRS->normalizedField) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s='1' ",addslashes($this->CDRS->normalizedField)); - $mongo_field = array_search($this->CDRS->normalizedField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = 1; } if ($this->CDRS->BillingPartyIdField && $this->BillingPartyId) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->BillingPartyIdField),addslashes($this->BillingPartyId)); - $mongo_field = array_search($this->CDRS->BillingPartyIdField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->BillingPartyId; } if (strlen($this->durationNormalized) && $this->durationNormalized != $this->duration) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s ='%s' ",addslashes($this->CDRS->durationField),addslashes($this->durationNormalized)); $this->duration=$this->durationNormalized; - $mongo_field = array_search($this->CDRS->durationField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = intval($this->durationNormalized); - } else { - $mongo_field = array_search($this->CDRS->durationField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = intval($this->duration); } if ($this->CDRS->DestinationIdField) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->DestinationIdField),addslashes($this->DestinationId)); - $mongo_field = array_search($this->CDRS->DestinationIdField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->DestinationId; } if ($this->CDRS->ResellerIdField) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->ResellerIdField),addslashes($this->ResellerId)); - $mongo_field = array_search($this->CDRS->ResellerIdField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->ResellerId; } if ($this->usernameNormalized && $this->usernameNormalized!=$this->username) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->usernameField),addslashes($this->usernameNormalized)); - $mongo_field = array_search($this->CDRS->usernameField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->usernameNormalized; } if ($this->aNumberNormalized && $this->aNumberNormalized!=$this->aNumber) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->aNumberField),addslashes($this->aNumberNormalized)); $this->aNumber=$this->aNumberNormalized; - $mongo_field = array_search($this->CDRS->aNumberField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->aNumberNormalized; } if ($this->CDRS->applicationField && $this->applicationNormalized) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->applicationField), addslashes($this->applicationNormalized)); $this->application=$this->applicationNormalized; - $mongo_field = array_search($this->CDRS->applicationField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->applicationNormalized; } if ($this->CDRS->flowField && $this->flow) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->flowField),addslashes($this->flow)); - $mongo_field = array_search($this->CDRS->flowField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->flow; } if ($this->domainNormalized && $this->domainNormalized != $this->domain) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->domainField),addslashes($this->domainNormalized)); $this->domainNumber=$this->domainNormalized; $this->domain=$this->domainNormalized; - $mongo_field = array_search($this->CDRS->domainField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->domainNormalized; } if ($this->cNumberNormalized && $this->cNumberNormalized!=$this->cNumber) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->cNumberField),addslashes($this->cNumberNormalized)); $this->cNumber=$this->cNumberNormalized; - $mongo_field = array_search($this->CDRS->cNumberField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->cNumberNormalized; } if ($this->CDRS->BillingIdField && $this->BillingId) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->BillingIdField),addslashes($this->BillingId)); - $mongo_field = array_search($this->CDRS->BillingIdField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->BillingId; } if ($this->CDRS->RemoteAddressField && $this->RemoteAddressNormalized && $this->RemoteAddressNormalized!= $this->RemoteAddress) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->RemoteAddressField),addslashes($this->RemoteAddressNormalized)); - $mongo_field = array_search($this->CDRS->RemoteAddressField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->RemoteAddressNormalized; } if ($this->CDRS->CanonicalURIField && $this->CanonicalURINormalized && $this->CanonicalURINormalized!= $this->CanonicalURI) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->CanonicalURIField),addslashes($this->CanonicalURINormalized)); - $mongo_field = array_search($this->CDRS->CanonicalURIField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->CanonicalURINormalized; } if ($this->stopTimeNormalized) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->stopTimeField),addslashes($this->stopTimeNormalized)); - $mongo_field = array_search($this->CDRS->stopTimeField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->stopTimeNormalized; } if ($this->CDRS->ratingEnabled && ($this->duration || $this->application == 'message')) { if ($this->DestinationId) { $Rate = new Rate($this->CDRS->rating_settings, $this->CDRS->cdrtool); if ($this->application == 'message') { $RateDictionary = array( 'callId' => $this->callId, 'timestamp' => $this->timestamp, 'duration' => $this->duration, 'DestinationId' => $this->DestinationId, 'BillingPartyId' => $this->BillingPartyId, 'ResellerId' => $this->ResellerId, 'domain' => $this->domain, 'gateway' => $this->gateway, 'RatingTables' => $this->CDRS->RatingTables, 'aNumber' => $this->aNumber, 'cNumber' => $this->cNumber ); $Rate->calculateMessage($RateDictionary); } else { $RateDictionary = array( 'callId' => $this->callId, 'timestamp' => $this->timestamp, 'duration' => $this->duration, 'DestinationId' => $this->DestinationId, 'inputTraffic' => $this->inputTraffic, 'outputTraffic' => $this->outputTraffic, 'BillingPartyId' => $this->BillingPartyId, 'ResellerId' => $this->ResellerId, 'domain' => $this->domain, 'gateway' => $this->gateway, 'RatingTables' => $this->CDRS->RatingTables, 'aNumber' => $this->aNumber, 'cNumber' => $this->cNumber, 'ENUMtld' => $this->ENUMtld, 'application' => $this->application ); $Rate->calculateAudio($RateDictionary); } $this->pricePrint = $Rate->pricePrint; $this->price = $Rate->price; $this->rateInfo = $Rate->rateInfo; $this->rateDuration = $Rate->duration; if ($Rate->broken_rate) { $this->broken_rate = true; } } else { $this->rateInfo = ''; $this->pricePrint = ''; $this->price = ''; } // strict mysql query fails when price is being set to '' if ($this->pricePrint === null || $this->pricePrint === '') { $this->pricePrint = '0.00'; } if ($this->CDRS->priceField) { if ($updatedFields) $query .= ", "; $updatedFields++; $query .= sprintf( " %s = '%s' ", addslashes($this->CDRS->priceField), addslashes($this->pricePrint) ); - $mongo_field = array_search($this->CDRS->priceField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = floatval($this->pricePrint); if ($this->CDRS->rateField ) { if ($updatedFields) $query .= ", "; $updatedFields++; $query.=sprintf(" %s = '%s' ",addslashes($this->CDRS->rateField),addslashes($this->rateInfo)); - $mongo_field = array_search($this->CDRS->rateField, $this->CDRS->CDRFields); - $this->mongo_cdr[$mongo_field] = $this->rateInfo; } } } $query1 = sprintf( "update %s set %s where %s = '%s'", addslashes($table), $query, addslashes($this->idField), addslashes($this->id)); dprint_sql($query1); - // TODO remove me, I am used to temporary sync mysql data with mongo data - if ($this->CDRS->mongo_table) { - $mongo_field = array_search($this->idField, $this->CDRS->CDRFields); - try { - $this->CDRS->mongo_table->update(array($mongo_field => $this->id), $this->mongo_cdr, array("upsert" => true)); - } catch (MongoException $e) { - printf("Caught Mongo exception: %s", $e->getMessage()); - } catch (Exception $e) { - printf("Caught exception: %s", $e->getMessage()); - } - } - if ($updatedFields) { if ($this->CDRS->CDRdb1->query($query1)) { if ($this->CDRS->CDRdb1->affected_rows()) { if ( $this->isBillingPartyLocal() && $table == "radacct".date('Ym')) { // cache usage only if current month $_traffic = ($this->inputTraffic + $this->outputTraffic) / 2; $_usage = array( 'calls' => 1, 'duration' => $this->duration, 'cost' => $this->price, 'cost_today' => $this->price, 'traffic' => $_traffic ); $this->cacheQuotaUsage($_usage); } } else { if (preg_match("/^(\w+)(\d{4})(\d{2})$/", $table, $m)) { $previousTable=$m[1].date('Ym', mktime(0, 0, 0, $m[3]-1, "01", $m[2])); $query2 = sprintf("update %s set %s where %s = '%s'",addslashes($previousTable),$query,addslashes($this->idField),addslashes($this->id)); if ($this->CDRS->CDRdb1->query($query2)) { if ($this->CDRS->CDRdb1->affected_rows()) { if ($this->isBillingPartyLocal() && $previousTable == "radacct".date('Ym')) { // cache usage only if current month $_traffic = ($this->inputTraffic + $this->outputTraffic) / 2; $_usage = array( 'calls' => 1, 'duration' => $this->duration, 'cost' => $this->price, 'cost_today' => $this->price, 'traffic' => $_traffic ); $this->cacheQuotaUsage($_usage); } } } else { $log = sprintf( "Database error: %s (%s)", $this->CDRS->CDRdb1->Error, $this->CDRS->CDRdb1->Errno ); syslog(LOG_NOTICE, $log); print($log); return 0; } } } return 1; } else { $log = sprintf( "Database error for query %s: %s (%s)", $query1, $this->CDRS->CDRdb1->Error, $this->CDRS->CDRdb1->Errno ); syslog(LOG_NOTICE, $log); print($log); return 0; } } } else { if ($this->CDRS->BillingPartyIdField && $CarrierInfo['BillingPartyId']) { $this->domain = $CarrierInfo['BillingDomain']; } if ($this->usernameNormalized && $this->usernameNormalized!=$this->username) { $this->username = $this->usernameNormalized; } if ($this->aNumberNormalized && $this->aNumberNormalized!=$this->aNumber) { $this->aNumber = $this->aNumberNormalized; } if ($this->domainNormalized && $this->domainNormalized != $this->domain) { $this->domainNumber = $this->domainNormalized; } if ($this->cNumberNormalized && $this->cNumberNormalized!=$this->cNumber) { $this->cNumber = $this->cNumberNormalized; } if ($this->CDRS->RemoteAddressField && $this->RemoteAddressNormalized && $this->RemoteAddressNormalized!= $this->RemoteAddress) { $this->RemoteAddress = $this->RemoteAddressNormalized; } } return 1; } function cacheQuotaUsage($usage) { if (!is_array($usage)) return ; $accounts[$this->BillingPartyId]['usage'] = $usage; $this->CDRS->cacheQuotaUsage($accounts); } function isCallerLocal() { return false; } function isCalleeLocal() { return false; } function isBillingPartyLocal() { return false; } function obfuscateCallerId() { global $obfuscateCallerId; if ($obfuscateCallerId) { } } function lookupRateFromNetwork($RateDictionary, $fp) { $this->rateInfo=''; $this->pricePrint=''; $this->price=''; $countEndofLines=0; $cmd="ShowPrice"; foreach (array_keys($RateDictionary) as $key) { $cmd .=" ".$key."=".$RateDictionary[$key]." "; } $this->price = 0; $this->pricePrint = ""; $this->rateInfo = ""; if (fputs($fp,"$cmd\n") !== false) { $i=0; while ($i < 100) { $i++; $line = fgets($fp,1024); if (!$line) { syslog(LOG_NOTICE, "Error: lookupRateFromNetwork(): connection to network socket died"); break; } if (preg_match("/^\n/",$line) || preg_match("/^END/",$line)) { break; } if ($i == 1) { $this->price = trim($line); $this->pricePrint = number_format($this->price, 4); continue; } $this->rateInfo.=$line; } } } function lookupGeoLocation($ip) { if ($_loc=geoip_record_by_name($ip)) { return $_loc['country_name'].'/'.$_loc['city']; } else if ($_loc=geoip_country_name_by_name($ip)) { return $_loc; } else { return ''; } } } function getLocalTime($timezone,$timestamp) { global $CDRTool; if (!$timezone || $timezone == $CDRTool['provider']['timezone']) { return date("Y-m-d H:i:s", $timestamp); } putenv("TZ=$timezone"); $startTimeLocal=date("Y-m-d H:i:s", $timestamp); $timezone=$CDRTool['provider']['timezone']; putenv("TZ=$timezone"); return $startTimeLocal; } function validDay($month,$day,$year) { if (!$month || !$year) { return $day; } while (1) { if (!checkdate($month,$day,$year) && $day) { $day--; next; } else { break; } } return $day; } // include CDRTool modules defined in global.inc if (is_array($CDRToolModules)) { foreach ($CDRToolModules as $module) { $module_filename="cdr_".$module.".php"; include($module_filename); } } function unLockNormalization ($dbid,$lockname) { $query=sprintf("SELECT RELEASE_LOCK('%s')",addslashes($lockname)); $log=sprintf("Unlock %s",$lockname); syslog(LOG_NOTICE, $log); if (!$dbid->query($query)) { $log="Error in unLockNormalization()"; syslog(LOG_NOTICE, $log); } } class SIPonline { function SIPonline ($datasource='',$database='db',$table='location') { global $CDRTool; $expandAll = $_REQUEST['expandAll']; $domain = $_REQUEST['domain']; $this->expandAll = $expandAll; $this->domain = $domain; $this->datasource = $datasource; if (strlen($CDRTool['filter']['domain'])) { $this->allowedDomains=explode(" ",$CDRTool['filter']['domain']); $allowed_domains_sql=""; $j=0; foreach ($this->allowedDomains as $_domain) { if ($j>0) $allowed_domains_sql.=","; $allowed_domains_sql.="'".addslashes($_domain)."'"; $j++; } } $this->locationDB = new $database; $this->locationTable = $table; $this->Registered=array(); $this->countUA=array(); $where = " where (1=1) " ; if ($allowed_domains_sql) { $where.= sprintf("and domain in (%s)",addslashes($allowed_domains_sql)) ; } $query=sprintf("select count(*) as c, domain from %s %s group by domain order by domain ASC", addslashes($this->locationTable), $where ); $this->locationDB->query($query); $this->domains=$this->locationDB->num_rows(); while ($this->locationDB->next_record()) { $this->Registered[$this->locationDB->f('domain')]=$this->locationDB->f('c'); $this->total=$this->total+$this->locationDB->f('c'); } $query=sprintf("select count(*) as c, user_agent from %s %s",addslashes($this->locationTable),$where); if ($this->domain) { $query.=sprintf(" and domain = '%s' ",addslashes($this->domain)); } $query.=" group by user_agent order by c DESC"; $this->locationDB->query($query); while ($this->locationDB->next_record()) { $this->countUA[$this->locationDB->f('user_agent')]=$this->locationDB->f('c'); } } function showHeader() { print ""; print " "; if ($this->domain) { print " "; } else { print " "; } print " "; } function showFooter() { print "
User@Domain SIP UA contact NAT address User Agent Expires Remain Users@ Domain
$this->total users@ $this->domains domains
"; } function showAll() { global $found; $this->showHeader(); foreach (array_keys($this->Registered) as $ld) { $onlines=$this->Registered[$ld]; if ($this->expandAll || ($this->domain && $this->domain==$ld)) { $this->show($ld); } else { $found++; $url = sprintf("%s?datasource=%s&domain=%s", $_SERVER['PHP_SELF'], urlencode($this->datasource), urlencode($ld) ); print " $found $onlines users@ $ld "; if ($this->domain) { print " "; } print " "; } } $this->showfooter(); /* print "

"; $this->showUAdistribution(); */ } function show() { global $found; $query="SELECT *, SEC_TO_TIME(UNIX_TIMESTAMP(expires)-UNIX_TIMESTAMP(NOW())) AS remain FROM location "; if ($this->domain) $query.=sprintf(" where domain = '%s'", addslashes($this->domain)); $query.= " ORDER BY domain ASC, username ASC "; $this->locationDB->query($query); while ($this->locationDB->next_record()) { $found++; $username = $this->locationDB->f('username'); $domain = $this->locationDB->f('domain'); $contact = $this->locationDB->f('contact'); $received = $this->locationDB->f('received'); $user_agent = $this->locationDB->f('user_agent'); $expires = $this->locationDB->f('expires'); $remain = $this->locationDB->f('remain'); $contact_print=substr($contact,4); $c_els=explode(";", $contact); $r_els=explode(";", $received); $transport="UDP"; if ($c_els[1] && preg_match("/transport=(tcp|tls)/i",$c_els[1],$m)) { $transport=strtoupper($m[1]); } $sip_account=$username."@".$domain; print " $found $sip_account $transport $c_els[0] $r_els[0] $user_agent $expires $remain "; $seen[$username]++; $seen[$domain]++; } } function showUAdistribution () { print ""; print " "; print ""; print ""; print ""; print " "; while (list($k,$v) = each($this->countUA)) { $users=$users+$v; $count++; print " "; print ""; print ""; print ""; print ""; } print " "; print ""; print ""; print ""; print " "; print "
User agentUsers
$count$k$v
$this->domain$users
"; } } class PrepaidHistory { function PrepaidHistory() { $this->db = new DB_cdrtool; } function purge($days=7) { $beforeDate=Date("Y-m-d", time()-$days*3600*24); $query=sprintf("delete from prepaid_history where date < '%s' and action like 'Debit balance%s'",addslashes($beforeDate),'%'); if (!$this->db->query($query)) { $log=sprintf ("Database error for query %s: %s (%s)\n",$query,$this->db->Error,$this->db->Errno); print $log; syslog(LOG_NOTICE,$log); } else { $log=sprintf ("Purged %d records from prepaid history before %s\n",$this->db->affected_rows(),$beforeDate); print $log; syslog(LOG_NOTICE,$log); } } } class CSVWritter { var $csv_directory = '/var/spool/cdrtool/normalize'; var $filename_extension = '.csv'; var $fields = array(); var $ready = false; var $cdr_type = array(); var $lines = 0; function CSVWritter($cdr_source='',$csv_directory='') { if ($cdr_source) { $this->cdr_source = $cdr_source; } else { $this->cdr_source = 'unknown'; } if ($csv_directory) { if (is_dir($csv_directory)) { $this->csv_directory = $csv_directory; } else { $log=sprintf ("CSV writter error: %s is not a directory\n",$csv_directory); syslog(LOG_NOTICE,$log); return false; } } $this->directory=$this->csv_directory."/".date("Ymd"); if (!is_dir($this->directory)) { if (!mkdir($this->directory)) { $log=sprintf ("CSV writter error: cannot create directory %s\n",$this->directory); syslog(LOG_NOTICE,$log); return false; } chmod($this->directory, 0775); } $this->directory_ready = true; } function open_file ($filename_suffix='') { if ($this->ready) return true; if (!$this->directory_ready) return false; if (!$filename_suffix) { $log=sprintf ("CSV writter error: no filename suffix provided\n"); syslog(LOG_NOTICE,$log); return false; } $this->filename_prefix = strtolower($this->cdr_source).'-'.date('YmdHi'); $this->full_path=rtrim($this->directory,'/').'/'.$this->filename_prefix.'-'.$filename_suffix.$this->filename_extension; $this->full_path_tmp=$this->full_path.'.tmp'; if (!$this->fp = fopen($this->full_path_tmp, 'w')) { $log=sprintf ("CSV writter error: cannot open %s for writing\n",$this->full_path_tmp); syslog(LOG_NOTICE,$log); return false; } $this->ready = true; return true; } function close_file () { if (!$this->ready) return false; fclose($this->fp); if (!rename($this->full_path_tmp, $this->full_path)) { $log=sprintf ("CSV writter error: cannot rename %s to %s\n",$this->full_path_tmp,$this->full_path); syslog(LOG_NOTICE,$log); } else { $log=sprintf ("%d normalized CDRs written to %s\n",$this->lines, $this->full_path); syslog(LOG_NOTICE,$log); } } function write_cdr ($CDR) { if (!$this->ready) return false; $line = sprintf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", $CDR->id, $CDR->callId, $CDR->flow, $CDR->application, $CDR->username, $CDR->CanonicalURI, $CDR->startTime, $CDR->stopTime, $CDR->duration, $CDR->DestinationId, $CDR->BillingPartyId, $CDR->ResellerId, $CDR->price ); if (!fputs($this->fp,$line)) { $this->ready = false; return false; } $this->lines++; return true; } } class MaxRate extends CSVWritter { var $skip_prefixes = array(); var $skip_numbers = array(); var $skip_domains = array(); var $rpid_cache = array(); var $translate_uris = array(); function MaxRate ($cdr_source='', $csv_directory='', $db_subscribers='') { global $MaxRateSettings; // set in global.inc /* $MaxRateSettings= array( 'translate_uris'=> array( '1233@10.0.0.2'=>'+1233', '[1-9][0-9]{4}.*@10.0.0.2'=>'+1233'), 'skip_domains' => array('example.net','10.0.0.1'), 'skip_numbers' => array('1233'), // skip CDRs that has the username part in this array 'skip_prefixes' => array('0031901') // skip CDRs that begin with any of this prefixes ); */ if (is_array($MaxRateSettings['skip_domains'])) { $this->skip_domains=$MaxRateSettings['skip_domains']; } if (is_array($MaxRateSettings['skip_numbers'])) { $this->skip_numbers=$MaxRateSettings['skip_numbers']; } if (is_array($MaxRateSettings['skip_prefixes'])) { $this->skip_prefixes=$MaxRateSettings['skip_prefixes']; } if (is_array($MaxRateSettings['translate_uris'])) { $this->translate_uris=$MaxRateSettings['translate_uris']; } $this->AccountsDB = new $db_subscribers(); $this->CSVWritter($cdr_source, $csv_directory); } function write_cdr($CDR) { if (!$this->ready) return false; # skip if no audio if ($CDR->application != 'audio') return true; # skip if no duration if (!$CDR->duration && ($CDR->disconnect != 200)) return true; # normalize destination if ($CDR->CanonicalURIE164) { $cdr['destination'] = '+'.$CDR->CanonicalURIE164; } else { $cdr['destination'] = $CDR->CanonicalURI; } list($canonical_username, $canonical_domain)=explode("@",$cdr['destination']); # skip domains if ($canonical_domain && in_array($canonical_domain,$this->skip_domains)) return true; # skip numbers if ($canonical_username && in_array($canonical_username,$this->skip_numbers)) return true; # skip prefixes if ($canonical_username && count($this->skip_prefixes)) { foreach ($this->skip_prefixes as $prefix) { if (preg_match("/^$prefix/",$canonical_username)) return true; } } # get RPID if caller is local if ($CDR->flow != 'incoming') { $CallerRPID=$this->getRPIDforAccount($CDR->aNumberPrint); } if ($CallerRPID) { # normalize RPID $cdr['origin'] = '0031'.ltrim($CallerRPID,'0'); } else { # normalize caller id numbers from PSTN gateway to 00format if (preg_match("/^\+?0([1-9][0-9]+)@(.*)$/",$CDR->aNumberPrint,$m)) { $cdr['origin'] = "0031".$m[1]; } else if (preg_match("/^\+?00([1-9][0-9]+)@(.*)$/",$CDR->aNumberPrint,$m)) { $cdr['origin'] = "00".$m[1]; } else if (preg_match("/^([1-9][0-9]+)@(.*)$/",$CDR->aNumberPrint,$m)) { $cdr['origin'] = "0031".$m[1]; } else if (preg_match("/^\+([1-9][0-9]+)@(.*)$/",$CDR->aNumberPrint,$m)) { $cdr['origin'] = "00".$m[1]; } else if (preg_match("/^anonymous@(.*)$/",$CDR->aNumberPrint) && $CDR->SipRPID) { if (preg_match("/^\+?0([1-9][0-9]+)$/",$CDR->SipRPID,$m)) { $cdr['origin'] = "0031".$m[1]; } else if (preg_match("/^\+?00([1-9][0-9]+)$/",$CDR->SipRPID,$m)) { $cdr['origin'] = "00".$m[1]; } else if (preg_match("/^([1-9][0-9]+)@(.*)$/",$CDR->SipRPID,$m)) { $cdr['origin'] = $m[1]; } else if (preg_match("/^\+([1-9][0-9]+)@(.*)$/",$CDR->SipRPID,$m)) { $cdr['origin'] = "00".$m[1]; } else if (preg_match("/^\+?0[0-9]?+@?(.*)?$/",$CDR->SipRPID,$m)) { $cdr['origin'] = "0031123456789"; } else if (preg_match("/^.*[a-zA-Z].*$/",$CDR->SipRPID,$m)) { $cdr['origin'] = "0031123456789"; } else if (preg_match("/^ims.imscore.net.*$/",$CDR->SipRPID,$m)) { $cdr['origin'] = "0031123456789"; } else { $cdr['origin'] = $CDR->SipRPID; } } else { $cdr['origin'] = "0031123456789"; //$cdr['origin'] = $CDR->aNumberPrint; } } # normalize short origins if (preg_match("/^\d{1,3}@.*$/",$cdr['origin'])) { $cdr['origin']='+31000000000'; } # normalize anonymous origins if (preg_match("/^anonymous@.*$/",$cdr['origin'])) { $cdr['origin']='+31000000000'; } #translate destination URIs to desired format if ($CDR->CanonicalURINormalized && count($this->translate_uris)) { foreach ($this->translate_uris as $key => $uri) { if ( preg_match("/^$key/", $CDR->CanonicalURINormalized)) { $cdr['destination']=$uri; break; } } } preg_match("/^(\d{4})-(\d{2})-(\d{2}) (\d{2}:\d{2}:\d{2})$/",$CDR->startTime,$m); $cdr['start_date'] = sprintf ("%s/%s/%s %s",$m[3],$m[2],$m[1],$m[4]); $cdr['diversion'] = ''; preg_match("/^(\d{4})-(\d{2})-(\d{2}) (\d{2}:\d{2}:\d{2})$/",$CDR->stopTime,$m); $cdr['stop_date'] = sprintf ("%s/%s/%s %s",$m[3],$m[2],$m[1],$m[4]); $cdr['product'] = $this->product; # normalize duration based on billed duration if ($CDR->rateDuration) { $cdr['duration'] = $CDR->rateDuration; } else { $cdr['duration'] = $CDR->duration; } $rate_info = explode("\n", $CDR->rateInfo); for ($i = 0; $i < sizeof($rate_info); ++$i) { //dprint_r($rate_info[$i]); if (strpos($rate_info[$i], "ProfileId:") !== false) { $cdr['profile'] = ltrim(str_replace("ProfileId: ", '', $rate_info[$i])); } } //$cdr['extra']="$CDR->callId"; list($cdr['username'],$cdr['domain'])= explode('@',$CDR->username); $cdr['charge_info'] = sprintf('"%s","%s","%s"',$CDR->price,$cdr['profile'],$CDR->destinationName); if ($CDR->flow == 'on-net') { # RFP 4.2.1 $CalleeRPID=$this->getRPIDforAccount($CDR->CanonicalURI); if ($CalleeRPID) { $cdr['destination'] = '0031'.ltrim($CalleeRPID,'0'); } $cdr['extra'] = $cdr['extra']."$CDR->flow"; } else if ($CDR->flow == 'outgoing') { # RFP 4.2.2 $cdr['extra'] = $cdr['extra']."$CDR->flow"; } else if ($CDR->flow == 'incoming') { # RFP 4.2.3 if ($this->inbound_trunks[$CDR->SourceIP]) { $inbound_trunk = $this->inbound_trunks[$CDR->SourceIP]; } else { $inbound_trunk = 'unknown'; } $cdr['username'] = $canonical_username; $CalleeRPID=$this->getRPIDforAccount($CDR->CanonicalURI); if ($CalleeRPID) { $cdr['destination'] = '0031'.ltrim($CalleeRPID,'0'); } $cdr['extra'] = $cdr['extra']."$CDR->flow"; } else if ($CDR->flow == 'diverted-on-net') { # RFP 4.2.4 $CalleeRPID=$this->getRPIDforAccount($CDR->CanonicalURI); $DiverterRPID=$this->getRPIDforAccount($CDR->username); if ($DiverterRPID) { $diverter_origin = '0031'.ltrim($DiverterRPID,'0'); } else { $diverter_origin = $CDR->username; } if ($CalleeRPID) { $cdr['c_num'] = '0031'.ltrim($CalleeRPID,'0'); } # Set destination to B-Number $cdr['destination'] = $diverter_origin; $cdr['diversion'] = $cdr['c_num']; $cdr['extra'] = $cdr['extra']."incoming-diverted-on-net"; } else if ($CDR->flow == 'diverted-off-net') { # RFP 4.2.5 $DiverterRPID=$this->getRPIDforAccount($CDR->username); if ($DiverterRPID) { $diverter_origin = '0031'.ltrim($DiverterRPID,'0'); } else { $diverter_origin = $CDR->username; } $cdr['c_num'] = $cdr['destination']; # Set destination to B-Number $cdr['destination']=$diverter_origin; $cdr['diversion'] = $cdr['c_num']; $cdr['extra'] = $cdr['extra']."incoming-diverted-off-net"; } else if ($CDR->flow == 'on-net-diverted-on-net') { # RFP 4.2.6 $DiverterRPID=$this->getRPIDforAccount($CDR->username); if ($DiverterRPID) { $diverter_origin = '0031'.ltrim($DiverterRPID,'0'); } else { $diverter_origin = $CDR->username; } $CalleeRPID=$this->getRPIDforAccount($CDR->CanonicalURI); if ($CalleeRPID) { $cdr['c_num'] = '0031'.ltrim($CalleeRPID,'0'); } # Set destination to B-Number $cdr['destination'] = $diverter_origin; $cdr['diversion'] = $cdr['c_num']; $cdr['extra'] = $cdr['extra']."$CDR->flow"; } else if ($CDR->flow == 'on-net-diverted-off-net') { # RFP 4.2.7 $DiverterRPID=$this->getRPIDforAccount($CDR->username); if ($DiverterRPID) { $diverter_origin = '0031'.ltrim($DiverterRPID,'0'); } else { $diverter_origin = $CDR->username; } $cdr['c_num']= $cdr['destination']; # Set destination to B-Number $cdr['destination'] = $diverter_origin; $cdr['diversion'] = $cdr['c_num']; $cdr['extra'] = $cdr['extra']."$CDR->flow"; } $cdr['username'] = preg_replace('/caiw0+|test0+/', "", $cdr['username']); $cdr['origin'] = str_replace('+','00',$cdr['origin']); $cdr['destination'] = str_replace('+','00',$cdr['destination']); $cdr['diversion'] = str_replace('+','00',$cdr['diversion']); $line = sprintf('"%s","%s","%s","%s","%s","%s","%s","%s","%s",%s'."\n", $CDR->callId, $cdr['origin'], $cdr['username'], $cdr['destination'], $cdr['diversion'], $cdr['start_date'], $cdr['stop_date'], $cdr['duration'], $cdr['extra'], $cdr['charge_info'] ); if (!fputs($this->fp,$line)) { $log=sprintf ("CSV writter error: cannot append to file %s\n",$this->full_path_tmp); syslog(LOG_NOTICE,$log); $this->close_file(); $this->ready = false; return false; } $this->lines++; return true; } function getRPIDforAccount($account) { if (!$account) return false; if ($this->rpid_cache[$account]) { return $this->rpid_cache[$account]; } list($username,$domain) = explode('@',$account); $query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'",addslashes($username),addslashes($domain)); if (!$this->AccountsDB->query($query)) { $log=sprintf ("Database error for query %s: %s (%s)",$query,$this->AccountsDB->Error,$this->AccountsDB->Errno); syslog(LOG_NOTICE,$log); return false; } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); $_profile=json_decode(trim($this->AccountsDB->f('profile'))); $this->rpid_cache[$account]=$_profile->rpid; return $_profile->rpid; } else { return false; } } } ?> diff --git a/library/cdr_opensips.php b/library/cdr_opensips.php index 3a643b8..e5e5469 100644 --- a/library/cdr_opensips.php +++ b/library/cdr_opensips.php @@ -1,5988 +1,5124 @@ 'RadAcctId', 'callId' => 'AcctSessionId', 'duration' => 'AcctSessionTime', 'startTime' => 'AcctStartTime', 'stopTime' => 'AcctStopTime', 'inputTraffic' => 'AcctInputOctets', 'outputTraffic' => 'AcctOutputOctets', 'flow' => 'ServiceType', 'aNumber' => 'CallingStationId', 'username' => 'UserName', 'domain' => 'Realm', 'cNumber' => 'CalledStationId', 'timestamp' => 'timestamp', 'SipMethod' => 'SipMethod', 'disconnect' => 'SipResponseCode', 'disconnectOrig' => 'AcctTerminateCause', 'SipFromTag' => 'SipFromTag', 'SipToTag' => 'SipToTag', 'RemoteAddress' => 'SipTranslatedRequestURI', 'SipCodec' => 'SipCodecs', 'SipUserAgents' => 'SipUserAgents', 'application' => 'SipApplicationType', 'BillingPartyId' => 'UserName', 'SipRPID' => 'SipRPID', 'SipProxyServer' => 'NASIPAddress', 'MediaRelay' => 'FramedIPAddress', 'gateway' => 'SourceIP', 'SourceIP' => 'SourceIP', 'SourcePort' => 'SourcePort', 'CanonicalURI' => 'CanonicalURI', 'normalized' => 'Normalized', 'rate' => 'Rate', 'price' => 'Price', 'DestinationId' => 'DestinationId', 'ResellerId' => 'BillingId', 'MediaInfo' => 'MediaInfo', 'RTPStatistics' => 'RTPStatistics', 'ENUMtld' => 'ENUMtld', 'UserAgent' => 'UserAgent', 'FromHeader' => 'FromHeader' ); public $CDRNormalizationFields = array( 'id' => 'RadAcctId', 'callId' => 'AcctSessionId', 'username' => 'UserName', 'domain' => 'Realm', 'gateway' => 'SourceIP', 'duration' => 'AcctSessionTime', 'startTime' => 'AcctStartTime', 'stopTime' => 'AcctStopTime', 'inputTraffic' => 'AcctInputOctets', 'outputTraffic' => 'AcctOutputOctets', 'aNumber' => 'CallingStationId', 'cNumber' => 'CalledStationId', 'timestamp' => 'timestamp', 'disconnect' => 'SipResponseCode', 'RemoteAddress' => 'SipTranslatedRequestURI', 'CanonicalURI' => 'CanonicalURI', 'SipRPID' => 'SipRPID', 'SipMethod' => 'SipMethod', 'application' => 'SipApplicationType', 'flow' => 'ServiceType', 'BillingPartyId' => 'UserName', 'ResellerId' => 'BillingId', 'price' => 'Price', 'DestinationId' => 'DestinationId', 'ENUMtld' => 'ENUMtld' ); public $GROUPBY = array( 'UserName' => 'SIP Billing Party', 'CallingStationId' => 'SIP Caller Party', 'SipRPID' => 'SIP Remote Party Id', 'CanonicalURI' => 'SIP Canonical URI', 'DestinationId' => 'SIP Destination Id', 'NASIPAddress' => 'SIP Proxy', 'FramedIPAddress' => 'Media Relay', 'MediaInfo' => 'Media Information', 'SourceIP' => 'Source IP', 'Realm' => 'SIP Billing domain', 'UserAgent' => 'User Agent', 'SipCodecs' => 'Codec type', 'SipApplicationType' => 'Application', 'SipResponseCode' => 'SIP status code', 'BillingId' => 'Tech prefix', 'ServiceType' => 'Call Flow', ' ' => '-------------', 'hour' => 'Hour of day', 'DAYOFWEEK' => 'Day of Week', 'DAYOFMONTH' => 'Day of Month', 'DAYOFYEAR' => 'Day of Year', 'BYMONTH' => 'Month', 'BYYEAR' => 'Year' ); public $FormElements = array( "begin_hour","begin_min","begin_month","begin_day","begin_year","begin_datetime","begin_time","end_time", "end_hour","end_min","end_month","end_day","end_year","end_datetime","end_date","begin_date", "call_id","sip_proxy", "media_relay", "a_number","a_number_comp","UserName","UserName_comp","BillingId", "c_number","c_number_comp","DestinationId","ExcludeDestinations", "NASPortId","Realm","Realms", "SipMethod","SipCodec","SipRPID","UserAgent", "application","sip_status","sip_status_class","gateway", "duration","action","MONTHYEAR", "order_by","order_type","group_by", "cdr_source","trace", "ReNormalize","media_info","cdr_table","maxrowsperpage", "flow" ); function initCDRFields() { // init names of CDR fields foreach (array_keys($this->CDRFields) as $field) { $mysqlField=$this->CDRFields[$field]; $_field=$field."Field"; $this->$_field=$mysqlField; } } function LoadDisconnectCodes() { $query="select * from sip_status order by code"; $this->disconnectCodesElements[]=array("label"=>"Any Status","value"=>""); $this->disconnectCodesElements[]=array("label"=>"Undefined (0)","value"=>"0"); $this->disconnectCodesClassElements[]=array("label"=>"Any Status Class","value"=>""); if ($this->cdrtool->query($query)) { while ($this->cdrtool->next_record()) { $key = $this->cdrtool->f('code'); $value = $this->cdrtool->f('description'); $value_print = $this->cdrtool->f('description')." (".$this->cdrtool->f('code').")"; if (preg_match("/^[^2-6]/", $key)) { continue; } $this->disconnectCodesElements[]=array("label"=>$value_print,"value"=>$key); $this->disconnectCodesDescription[$key]=$value; $class = substr($key, 0, 1); $class_text = substr($key, 0, 1)."XX (".$this->cdrtool->f('code_type').")"; if (!$seen[$class]) { $this->disconnectCodesClassElements[]=array("label"=>$class_text,"value"=>substr($key, 0, 1)); $this->disconnectCodesClassDescription[substr($key, 0, 1)]=$class_text; $seen[$class]++; } $i++; } } } function showTableHeader() { print " "; } function showExportHeader() { print "id,StartTime,StopTime,BillingParty,BillingDomain,PSTNCallerId,CallerParty,CalledParty,DestinationId,DestinationName,RemoteAddress,CanonicalURI,Duration,Price,SIPProxy,Caller KBIn,Called KBIn,CallingUserAgent,CalledUserAgent,StatusCode,StatusName,Codec,Media\n"; } function showTableHeaderSubscriber() { if (!$this->export) { print "
Id Start Time Media/Flow SIP Caller Caller Location Sip Proxy Media Relay SIP Destination Dur Price KBIn KBOut Status
"; } else { print "id,StartTime,StopTime,SIPBillingParty,SIPBillingDomain,RemotePartyId,CallerParty,CalledParty,DestinationId,DestinationName,RemoteAddress,CanonicalURI,Duration,Price,SIPProxy,Applications,Caller KBIn,Called KBIn,CallingUserAgent,CalledUserAgent,StatusCode,StatusName,Codec,Application\n"; } } function showTableHeaderStatistics() { $group_byPrint=$this->GROUPBY[$this->group_byOrig]; if (!$this->export) { print "
Id Start Time SIP Caller Caller Location Sip Proxy SIP Destination Duration Price KBIn KBOut
"; } else { print "id,Calls,Seconds,Minutes,Hours,Price,TrafficIn(MB),TrafficOut(MB),Success(%),Success(calls),Failure(%),Failure(calls),$group_byPrint,Description\n"; } } function initForm() { // form els added below must have global vars foreach ($this->FormElements as $_el) { global ${$_el}; ${$_el} = trim($_REQUEST[$_el]); } $action = "search"; if ($this->CDRTool['filter']['gateway']) { $gateway=$this->CDRTool["filter"]["gateway"]; } if ($this->CDRTool['filter']['aNumber']) { $UserName=$this->CDRTool['filter']['aNumber']; } if ($this->CDRTool['filter']['domain']) { $Realm = $this->CDRTool['filter']['domain']; } if (!$maxrowsperpage) { $maxrowsperpage=15; } $this->f = new form; if (isset($this->CDRTool['dataSourcesAllowed'])) { while (list($k, $v)=each($this->CDRTool['dataSourcesAllowed'])) { if ($this->DATASOURCES[$v]['invisible']) continue; $cdr_source_els[]=array("label"=>$this->DATASOURCES[$v]['name'],"value"=>$v); } } if (!$cdr_source) { $cdr_source=$cdr_source_els[0]['value']; } $this->f->add_element( array( "name"=>"cdr_source", "type"=>"select", "options"=>$cdr_source_els, "size"=>"1", "extrahtml"=>"class=span2 onChange=\"document.datasource.submit.disabled = true; location.href = 'callsearch.phtml?cdr_source=' + this.options[this.selectedIndex].value\"", "value"=>"$cdr_source" ) ); $cdr_table_els = array(); foreach ($this->tables as $_table) { if (preg_match("/^.*(\d{6})$/", $_table, $m)) { $cdr_table_els[]=array("label"=>$m[1],"value"=>$_table); } else { $cdr_table_els[]=array("label"=>$_table,"value"=>$_table); } } $this->f->add_element( array( "name"=>"cdr_table", "type"=>"select", "options"=>$cdr_table_els, "size"=>"1", "class"=>"span2", "value"=>$cdr_table, "extrahtml"=>"class=span2" ) ); if ($begin_datetime) { preg_match("/^(\d\d\d\d)-(\d+)-(\d+)\s+(\d\d):(\d\d)/", "$begin_datetime", $parts); $begin_year = date(Y, $begin_datetime); $begin_month = date(m, $begin_datetime); $begin_day = date(d, $begin_datetime); $begin_hour = date(H, $begin_datetime); $begin_min = date(i, $begin_datetime); } else { $begin_day = $_REQUEST["begin_day"]; $begin_month = $_REQUEST["begin_month"]; $begin_year = $_REQUEST["begin_year"]; $begin_hour = $_REQUEST["begin_hour"]; $begin_min = $_REQUEST["begin_min"]; list($begin_hour, $begin_min)=explode(":", $begin_time); list($begin_year, $begin_month, $begin_day)=explode("-", $begin_date); } if ($end_datetime) { preg_match("/^(\d\d\d\d)-(\d+)-(\d+)\s+(\d\d):(\d\d)/", "$end_datetime", $parts); $end_year = date(Y, $end_datetime); $end_month = date(m, $end_datetime); $end_day = date(d, $end_datetime); $end_hour = date(H, $end_datetime); $end_min = date(i, $end_datetime); } else { $end_day = $_REQUEST["end_day"]; $end_month = $_REQUEST["end_month"]; $end_year = $_REQUEST["end_year"]; $end_hour = $_REQUEST["end_hour"]; $end_min = $_REQUEST["end_min"]; list($end_hour, $end_min)=explode(":", $end_time); list($end_year, $end_month, $end_day)=explode("-", $end_date); } // corect last day of the month to be valid day $begin_day = validDay($begin_month, $begin_day, $begin_year); $end_day = validDay($end_month, $end_day, $end_year); $default_year = Date("Y"); $default_month = Date("m"); $default_day = Date("d"); $default_hour = Date(H, time()); if ($default_hour > 1) { $default_hour=$default_hour-1; } $default_hour = preg_replace("/^(\d)$/", "0$1", $default_hour); $default_min = Date("i"); if ($default_min > 10) { $default_min = $default_min-10; $default_min = preg_replace("/^(\d)$/", "0$1", $default_min); } if (!$begin_hour) $begin_hour = $default_hour; if (!$begin_min) $begin_min = $default_min; if (!$begin_day) $begin_day = $default_day; if (!$begin_month) $begin_month = $default_month; if (!$begin_year) $begin_year = $default_year; if (!$end_hour) $end_hour = 23; if (!$end_min) $end_min = 55; if (!$end_day) $end_day = $default_day; if (!$end_month) $end_month = $default_month; if (!$end_year) $end_year = $default_year; $this->f->add_element( array( "name"=>"begin_time", "size"=>"1", "type"=>"text", "extrahtml"=>"id='timepicker1' class=\"input-small\" data-show-meridian='false' data-minute-step='1' data-default-time='$begin_hour:$begin_min'" ) ); $this->f->add_element( array( "name"=>"end_time", "size"=>"1", "type"=>"text", "extrahtml"=>"id='timepicker2' class=\"input-small\" data-show-meridian='false' data-minute-step='1' data-default-time='$end_hour:$end_min'" ) ); $this->f->add_element( array( "name"=>"call_id", "type"=>"text", "size"=>"50", "maxlength"=>"100", "extrahtml"=>"class=span4" ) ); $this->f->add_element( array( "name"=>"UserName", "type"=>"text", "size"=>"25", "maxlength"=>"255", "extrahtml"=>"class=span2" ) ); $this->f->add_element( array( "name"=>"a_number", "type"=>"text", "size"=>"25", "maxlength"=>"255", "extrahtml"=>"class=span2" ) ); $this->f->add_element( array( "name"=>"BillingId", "type"=>"text", "size"=>"25", "maxlength"=>"255", "extra_html"=>"class=span2" ) ); $this->f->add_element( array( "name"=>"c_number", "type"=>"text", "size"=>"25", "maxlength"=>"255", "extrahtml"=>"class=span2" ) ); $this->f->add_element( array( "name" => "sip_status", "type" => "select", "options" => $this->disconnectCodesElements, "size" => "1", "value" => $sip_status, "extrahtml" => "class=span3" ) ); $this->f->add_element( array( "name" => "sip_status_class", "type" => "select", "options" => $this->disconnectCodesClassElements, "size" => "1", "extrahtml" => "class=span3" ) ); if (!$this->CDRTool['filter']['aNumber']) { $durations_els = array( array("label"=>"All calls","value"=>""), array("label"=>"0 seconds","value"=>"zero"), array("label"=>"non 0 seconds","value"=>"nonzero"), array("label"=>"non 0 seconds without price","value"=>"zeroprice"), array("label"=>"less than 5 seconds","value"=>"< 5"), array("label"=>"more than 5 seconds","value"=>"> 5"), array("label"=>"less than 60 seconds","value"=>"< 60"), array("label"=>"more than 2 minutes","value"=>"> 120"), array("label"=>"greater than 1 hour","value"=>"> 3600"), array("label"=>"one hour","value"=>"onehour"), array("label"=>"greater than 5 hours","value"=>"> 18000"), array("label"=>"Un-normalized calls","value"=>"unnormalized"), array("label"=>"Un-normalized calls > 0s","value"=>"unnormalized_duration"), array("label"=>"One way media","value"=>"onewaymedia"), array("label"=>"No media","value"=>"nomedia") ); } else { $durations_els = array( array("label"=>"All calls","value"=>""), array("label"=>"0 seconds call","value"=>"zero"), array("label"=>"Succesfull calls","value"=>"nonzero"), array("label"=>"less than 60 seconds","value"=>"< 60"), array("label"=>"greater than 1 hour","value"=>"> 3600") ); $this->GROUPBY = array( 'UserName' => 'SIP Billing Party', 'CallingStationId' => 'SIP Caller Party', 'DestinationId' => 'SIP Destination Id', 'SipApplicationType' => 'Application', ' ' => '-------------', 'hour' => 'Hour of day', 'DAYOFWEEK' => 'Day of Week', 'DAYOFMONTH' => 'Day of Month', 'DAYOFYEAR' => 'Day of Year', 'BYMONTH' => 'Month', 'BYYEAR' => 'Year' ); } $flow_els = array( array("label"=>"Any Call Flow","value"=>""), array("label"=>"On Net","value"=>"on-net"), array("label"=>"Incoming","value"=>"incoming"), array("label"=>"Outgoing","value"=>"outgoing"), array("label"=>"Transit","value"=>"transit"), array("label"=>"Diverted On Net","value"=>"diverted-on-net"), array("label"=>"Diverted Off Net","value"=>"diverted-off-net"), array("label"=>"On Net Diverted On Net","value"=>"on-net-diverted-on-net"), array("label"=>"On Net Diverted Off Net","value"=>"on-net-diverted-off-net"), array("label"=>"Unknown Flow","value"=>"Sip-Session") ); $this->f->add_element(array( "name"=>"flow", "type"=>"select", "options"=>$flow_els, "value"=>"", "size"=>"1", "extrahtml"=>"class=span3" )); $this->f->add_element(array( "name"=>"duration", "type"=>"select", "options"=>$durations_els, "value"=>"All", "size"=>"1", "extrahtml"=>"class=span3" )); $comp_ops_els = array( array("label"=>"Begins with","value"=>"begin"), array("label"=>"Contains","value"=>"contain"), array("label"=>"Is empty","value"=>"empty"), array("label"=>"Equal","value"=>"equal") ); $this->f->add_element(array( "name"=>"a_number_comp", "type"=>"select", "options"=>$comp_ops_els, "value"=>"begin", "size"=>"1", "extrahtml"=>"class=span2" )); $this->f->add_element(array( "name"=>"c_number_comp", "type"=>"select", "options"=>$comp_ops_els, "value"=>"begin", "size"=>"1", "extrahtml"=>"class=span2" )); $this->f->add_element(array( "name"=>"UserName_comp", "type"=>"select", "options"=>$comp_ops_els, "value"=>"begin", "size"=>"1", "extrahtml"=>"class=span2" )); $this->f->add_element(array( "name"=>"Realm", "type"=>"text", "size"=>"25", "maxlength"=>"25", "extrahtml"=>"class=span2" )); $media_info_els=array( array("label"=>"","value"=>""), array("label"=>"Timeout","value"=>"timeout"), array("label"=>"ICE session","value"=>"ICE session") ); $this->f->add_element(array( "name"=>"media_info", "type"=>"select", "options"=>$media_info_els, "size"=>"1", "value"=>"", "extrahtml"=>"class=span2" )); $this->f->add_element(array("type"=>"submit", "name"=>"submit", "value"=>"Search","extrahtml"=>"class=btn" )); $max_els = array( array("label"=>"5","value"=>"5"), array("label"=>"10","value"=>"10"), array("label"=>"15","value"=>"15"), array("label"=>"25","value"=>"25"), array("label"=>"50","value"=>"50"), array("label"=>"100","value"=>"100"), array("label"=>"500","value"=>"500") ); $this->f->add_element(array( "name"=>"maxrowsperpage", "type"=>"select", "options"=>$max_els, "size"=>"1", "value"=>"25", "extrahtml"=>"class = span2" )); $order_type_els = array( array("label"=>"Descending","value"=>"DESC"), array("label"=>"Ascending","value"=>"ASC") ); $this->f->add_element(array( "name"=>"order_type", "type"=>"select", "options"=>$order_type_els, "size"=>"1", "extrahtml"=>"class=span2" )); $this->f->add_element(array("type"=>"hidden", "name"=>"action", "value"=>$action )); $order_by_els = array(array("label"=>"Id","value"=>"RadAcctId"), array("label"=>"Date","value"=>"AcctStopTime"), array("label"=>"Billing Party","value"=>"UserName"), array("label"=>"Remote Party Id","value"=>"SipRPID"), array("label"=>"Caller Party","value"=>"CallingStationId"), array("label"=>"Destination","value"=>"CalledStationId"), array("label"=>"Duration","value"=>"AcctSessionTime"), array("label"=>"Input traffic","value"=>"AcctInputOctets"), array("label"=>"Output traffic","value"=>"AcctOutputOctets"), array("label"=>"Price","value"=>"Price"), array("label"=>"Failures(%)","value"=>"zeroP"), array("label"=>"Success(%)","value"=>"nonzeroP"), array("label"=>"Group by","value"=>"group_by") ); $group_by_els[]=array("label"=>"","value"=>""); while (list($k,$v)=each($this->GROUPBY)) { $group_by_els[]=array("label"=>$v,"value"=>$k); } $this->f->add_element( array( "name"=>"order_by", "type"=>"select", "options"=>$order_by_els, "value"=>$order_by, "size"=>"1", "extrahtml"=>"class=span3" ) ); $this->f->add_element(array("name"=>"group_by", "type"=>"select", "options"=>$group_by_els, "value"=>$group_by, "size"=>"1", "extrahtml"=>"class=span3" )); $application_els = array( array("label"=>"Any Application", "value"=>""), array("label"=>"Audio", "value"=>"audio"), array("label"=>"Video", "value"=>"video"), array("label"=>"Message" , "value"=>"message"), array("label"=>"IM Chat" , "value"=>"chat"), array("label"=>"Audio + Chat" , "value"=>"audio=2C chat"), array("label"=>"File Transfer","value"=>"file-transfer") ); $this->f->add_element(array("name"=>"application", "type"=>"select", "options"=>$application_els, "value"=>$application, "size"=>"1", "extrahtml"=>"class=span2" )); $this->f->add_element(array("name"=>"UserAgent", "type"=>"text", "size"=>"25", "maxlength"=>"50", "value"=>$UserAgent, "extrahtml"=>"class=span2" )); $this->f->add_element(array("name"=>"SipCodec", "type"=>"text", "size"=>"10", "maxlength"=>"50", "value"=>$SipCodec, "extrahtml"=>"class=span2" )); $this->f->add_element( array( "name"=>"sip_proxy", "type"=>"text", "size"=>"25", "maxlength"=>"255", "value"=>$sip_proxy, "extrahtml"=>"class=span2" ) ); $this->f->add_element( array( "name"=>"media_relay", "type"=>"text", "size"=>"25", "maxlength"=>"255", "value"=>$media_proxy, "extrahtml"=>"class=span2" ) ); $this->f->add_element( array( "name"=>"gateway", "type"=>"text", "size"=>"25", "maxlength"=>"255", "value"=>$gateway, "extrahtml"=>"class=span2" ) ); $this->f->add_element( array( "name"=>"DestinationId", "type"=>"text", "size"=>"10", "extrahtml"=>"class=span3" ) ); $this->f->add_element( array( "name"=>"ExcludeDestinations", "type"=>"text", "size"=>"20", "maxlength"=>"255", "extrahtml"=>"class=span3" ) ); $this->f->load_defaults(); $this->f->add_element( array( "name"=>"begin_date", "size"=>"10", "maxlength"=>"10", "type"=>"text", "value" => "$begin_year-$begin_month-$begin_day", "extrahtml"=>"id='begin_date' data-date-format=\"yyyy-mm-dd\" class=\"span2\"" ) ); $this->f->add_element(array( "name"=>"end_date", "size"=>"1", "type"=>"text", "value"=>"$end_year-$end_month-$end_day", "extrahtml"=>"id='end_date' data-date-format=\"yyyy-mm-dd\" class=\"span2\"" )); } function searchForm() { global $perm; $this->initForm(); $this->f->start("", "POST", "", "", "datasource"); print "
Calls Seconds Minutes Hours Price TrafficIn(MB) TrafficOut(MB) Success Failure $group_byPrint Description Action
"; $this->showDataSources($this->f); $this->showDateTimeElements($this->f); // freeze some form els if ($this->CDRTool['filter']['aNumber']) { $ff[]="a_number"; $ff[]="a_number_comp"; $ff[]="UserName"; $ff[]="UserName_comp"; } if ($this->CDRTool['filter']['domain']) { $Realm=$this->CDRTool['filter']['domain']; $ff[]="Realm"; } if ($this->CDRTool['filter']['gateway']) { $gateway=$this->CDRTool['filter']['gateway']; $ff[]="gateway"; } if (count($ff)) { $this->f->freeze($ff); } print " "; print " "; print " "; print " "; print " "; print " "; print " "; print " "; print "

"; $this->f->show_element("submit", ""); $this->f->finish(); print "
"; } function searchFormSubscriber() { global $perm; $this->initForm(); $this->f->start("", "POST", "", "", "datasource"); print " "; $this->showDataSources($this->f); $this->showDateTimeElements($this->f); // freeze some form els if ($this->CDRTool['filter']['aNumber']) { $ff[]="UserName"; } if ($this->CDRTool['filter']['domain']) { $ff[]="Realm"; } if ($this->CDRTool["filter"]["gateway"]) { $ff[]="gateway"; } if (count($ff)) { $this->f->freeze($ff); } print " "; print " "; print " "; print " "; print " "; print "

"; $this->f->show_element("submit", ""); $this->f->finish(); print "
"; } function show() { global $perm; if (!is_object($this->CDRdb)) { $log = sprintf("Error: CDR database is not initalized"); print $log; return false; } foreach ($this->FormElements as $_el) { ${$_el} = trim($_REQUEST[$_el]); } if ($begin_time) { list($begin_hour, $begin_min)=explode(":", $begin_time); } if ($end_time) { list($end_hour, $end_min)=explode(":", $end_time); } if ($begin_date) { list($begin_year, $begin_month, $begin_day)=explode("-", $begin_date); } if ($end_date) { list($end_year, $end_month, $end_day)=explode("-", $end_date); } // overwrite some elements based on user rights if ($this->CDRTool['filter']['gateway']) { $gateway =$this->CDRTool['filter']['gateway']; } if (!$this->export) { if (!$begin_datetime) { $begin_datetime="$begin_year-$begin_month-$begin_day $begin_hour:$begin_min"; $begin_datetime_timestamp = mktime($begin_hour, $begin_min, 0, $begin_month, $begin_day, $begin_year); } else { $begin_datetime_timestamp=$begin_datetime; $begin_datetime = Date("Y-m-d H:i", $begin_datetime); } if (!$end_datetime) { $end_datetime_timestamp = mktime($end_hour, $end_min, 0, $end_month, $end_day, $end_year); $end_datetime="$end_year-$end_month-$end_day $end_hour:$end_min"; } else { $end_datetime_timestamp=$end_datetime; $end_datetime = Date("Y-m-d H:i", $end_datetime); } } else { $begin_datetime = Date("Y-m-d H:i", $begin_datetime); $end_datetime = Date("Y-m-d H:i", $end_datetime); } if (!$order_by || (!$group_by && $order_by == "group_by")) { $order_by=$this->idField; } if (!$cdr_table) { $cdr_table=$this->table; } $this->url = sprintf("?cdr_source=%s&cdr_table=%s", $this->cdr_source, $cdr_table); if ($this->CDRTool['filter']['domain']) { $this->url .= sprintf("&Realms=%s", urlencode($this->CDRTool['filter']['domain'])); $Realms = explode(" ", $this->CDRTool['filter']['domain']); } elseif ($Realms) { $this->url .= sprintf("&Realms=%s", urlencode($Realms)); $Realms = explode(" ", $Realms); } if ($this->CDRTool['filter']['aNumber']) { $this->url .= sprintf("&UserName=%s", urlencode($this->CDRTool['filter']['aNumber'])); } if ($this->CDRTool['filter']['after_date']) { $where .= sprintf(" and %s >= '%s' ", addslashes($this->startTimeField), addslashes($this->CDRTool['filter']['after_date'])); } if ($order_by) { $this->url.=sprintf("&order_by=%s&order_type=%s", addslashes($order_by), addslashes($order_type)); } $this->url.=sprintf("&begin_datetime=%s", urlencode($begin_datetime_timestamp)); $this->url.=sprintf("&end_datetime=%s", urlencode($end_datetime_timestamp)); if (!$call_id && $begin_datetime && $end_datetime) { $where .= sprintf( " (%s >= '%s' and %s < '%s') ", addslashes($this->startTimeField), addslashes($begin_datetime), addslashes($this->startTimeField), addslashes($end_datetime) ); } else { $where .= sprintf(" (%s >= '1970-01-01' ) ", addslashes($this->startTimeField)); } if ($MONTHYEAR) { $where .= sprintf(" and %s like '%s%s' ", addslashes($this->startTimeField), addslashes($MONTHYEAR), '%'); $this->url.= sprintf("&MONTHYEAR=%s", urlencode($MONTHYEAR)); } if ($flow) { $this->url.=sprintf("&flow=%s", urlencode($flow)); $where .= sprintf(" and %s = '%s' ", addslashes($this->flowField), addslashes($flow)); } if ($this->CDRTool['filter']['aNumber']) { // force user to see only CDRS with his a_numbers $where .= sprintf( " and ( %s = '%s' or %s = '%s') ", addslashes($this->usernameField), addslashes($this->CDRTool['filter']['aNumber']), addslashes($this->CanonicalURIField), addslashes($this->CDRTool['filter']['aNumber']) ); $UserName_comp='equal'; $UserName=$this->CDRTool['filter']['aNumber']; } if ($UserName_comp == "empty") { $where .= sprintf(" and %s = ''", addslashes($this->usernameField)); $this->url.=sprintf("&UserName_comp=%s", urlencode($UserName_comp)); } elseif (strlen($UserName) && !$this->CDRTool['filter']['aNumber']) { if (!$UserName_comp) { $UserName_comp='begin'; } if ($UserName_comp=="begin") { $where .= sprintf(" and %s like '%s%s'", addslashes($this->usernameField), addslashes($UserName), '%'); } elseif ($UserName_comp=="contain") { $where .= sprintf(" and %s like '%s%s%s'", addslashes($this->usernameField), '%', addslashes($UserName), '%'); } elseif ($UserName_comp=="equal") { $where .= sprintf(" and %s = '%s'", addslashes($this->usernameField), addslashes($UserName)); } else { $where .= sprintf(" and %s = ''", addslashes($this->usernameField)); } $this->url.= sprintf("&UserName=%s&UserName_comp=%s", urlencode($UserName), $UserName_comp); } $a_number = trim($a_number); if ($a_number_comp == "empty") { $where .= sprintf(" and %s = ''", addslashes($this->aNumberField)); $this->url.=sprintf("&a_number_comp=%s", urlencode($a_number_comp)); } elseif (strlen($a_number)) { $a_number = urldecode($a_number); if (!$a_number_comp) { $a_number_comp = "equal"; } $this->url.=sprintf("&a_number=%s", urlencode($a_number)); if ($a_number_comp=="begin") { $where .= sprintf(" and %s like '%s%s'", addslashes($this->aNumberField), addslashes($a_number), '%'); } elseif ($a_number_comp=="contain") { $where .= sprintf(" and %s like '%s%s%s'", addslashes($this->aNumberField), '%', addslashes($a_number), '%'); } elseif ($a_number_comp=="equal") { $where .= sprintf(" and %s = '%s'", addslashes($this->aNumberField), addslashes($a_number)); } $this->url.=sprintf("&a_number_comp=%s", urlencode($a_number_comp)); } $c_number = trim($c_number); if ($c_number_comp == "empty") { $where .= sprintf(" and %s = ''", addslashes($this->CanonicalURIField)); $this->url.=sprintf("&c_number_comp=%s", urlencode($c_number_comp)); } elseif (strlen($c_number)) { $c_number = urldecode($c_number); if (!$c_number_comp) { $c_number_comp = "begin"; } if (!$c_number_comp || $c_number_comp == "begin") { $where .= sprintf(" and %s like '%s%s'", addslashes($this->CanonicalURIField), addslashes($c_number), '%'); } elseif ($c_number_comp=="contain") { $where .= sprintf(" and %s like '%s%s%s'", addslashes($this->CanonicalURIField), '%', addslashes($c_number), '%'); } elseif ($c_number_comp=="equal") { $where .= sprintf(" and %s = '%s'", addslashes($this->CanonicalURIField), addslashes($c_number)); } $this->url.=sprintf("&c_number=%s&c_number_comp=%s", urlencode($c_number), urlencode($c_number_comp)); } $Realm = trim($Realm); if ($Realms) { $where .= sprintf(" and ("); $count_realms = count($Realms); $j = 1; foreach ($Realms as $realm) { $where .= sprintf(" ( %s like '%%%s' or %s like '%%%s' ) ", $this->domainField, addslashes($realm), $this->CanonicalURIField, addslashes($realm)); if ($j < $count_realms) { $where .= " or "; } $j = $j + 1; } $where .= ") "; } elseif ($Realm) { $Realm = urldecode($Realm); $where .= sprintf(" and %s like '%s' ", $this->domainField, addslashes($Realm)); $this->url.=sprintf("&Realm=%s", urlencode($Realm)); } $BillingId = trim($BillingId); if (preg_match("/^\d+$/", $BillingId) && $this->BillingIdField) { $where .= " and $this->BillingIdField = '".addslashes($BillingId)."'"; $this->url.=sprintf("&BillingId=%s", urlencode($BillingId)); } if ($application) { $where .= " and $this->applicationField like '%".addslashes($application)."%'"; $this->url.=sprintf("&application=%s", urlencode($application)); } if ($DestinationId) { if ($DestinationId=="empty") { $DestinationIdSQL = ""; } else { $DestinationIdSQL = $DestinationId; } $where .= " and $this->DestinationIdField = '".addslashes($DestinationIdSQL)."'"; $this->url.=sprintf("&DestinationId=%s", urlencode($DestinationId)); } if (strlen(trim($ExcludeDestinations))) { $ExcludeDestArray = explode(" ", trim($ExcludeDestinations)); foreach ($ExcludeDestArray as $exclDst) { if (preg_match("/^0+(\d+)$/", $exclDst, $m)) { $exclDest_id = $m[1]; } else { $exclDest_id = $exclDst; } $where .= " and ". $this->CanonicalURIField. " not like '". addslashes(trim($exclDst)). "'"; } $this->url .= sprintf("&ExcludeDestinations=%s", urlencode($ExcludeDestinations)); } $call_id = trim($call_id); if ($call_id) { $call_id = urldecode($call_id); $where .= " and $this->callIdField = '".addslashes($call_id)."'"; $this->url.=sprintf("&call_id=%s", urlencode($call_id)); } if ($sip_proxy) { $sip_proxy = urldecode($sip_proxy); $where .= " and $this->SipProxyServerField = '".addslashes($sip_proxy)."'"; $this->url.=sprintf("&sip_proxy=%s", urlencode($sip_proxy)); } if ($media_relay) { $media_relay = urldecode($media_relay); $where .= " and $this->MediaRelayField = '".addslashes($media_relay)."'"; $this->url.=sprintf("&media_relay=%s", urlencode($media_relay)); } if ($SipCodec) { $this->url.=sprintf("&SipCodec=%s", urlencode($SipCodec)); if ($SipCodec != "empty") { $where .= " and $this->SipCodecField = '".addslashes($SipCodec)."'"; } else { $where .= " and $this->SipCodecField = ''"; } } if ($SipRPID) { $this->url.=sprintf("&SipRPID=%s", urlencode($SipRPID)); if ($SipRPID != "empty") { $where .= " and $this->SipRPIDField = '".addslashes($SipRPID)."'"; } else { $where .= " and $this->SipRPIDField = ''"; } } if ($UserAgent) { $where .= " and $this->UserAgentField like '%".addslashes($UserAgent)."%'"; $this->url.=sprintf("&UserAgent=%s", urlencode($UserAgent)); } if (strlen($sip_status)) { $where .= " and $this->disconnectField ='".addslashes($sip_status)."'"; $this->url.=sprintf("&sip_status=%s", urlencode($sip_status)); } if ($sip_status_class) { $where .= " and $this->disconnectField like '$sip_status_class%'"; $this->url.=sprintf("&sip_status_class=%s", urlencode($sip_status_class)); } if ($this->CDRTool[filter]["gateway"]) { $gatewayFilter=$this->CDRTool[filter]["gateway"]; $where .= " and $this->gatewayField = '".addslashes($gatewayFilter)."'"; } elseif ($gateway) { $gateway = urldecode($gateway); $where .= " and $this->gatewayField = '".addslashes($gateway)."'"; $this->url.=sprintf("&gateway=%s", urlencode($gateway)); } if ($duration) { if (preg_match("/\d+/", $duration)) { $where .= " and ($this->durationField > 0 and $this->durationField $duration) "; } elseif (preg_match("/onehour/", $duration)) { $where .= " and ($this->durationField < 3610 and $this->durationField > 3530) "; } elseif ($duration == "zero") { $where .= " and $this->durationField = 0"; } elseif ($duration == "zeroprice" && $this->priceField) { $where .= " and $this->durationField > 0 and ($this->priceField = '' or $this->priceField is NULL)"; - $mongo_where[$this->priceField] = ''; } elseif ($duration == "nonzero") { $where .= " and $this->durationField > 0"; } elseif ($duration == "onewaymedia") { $where .= " and (($this->inputTrafficField > 0 && $this->outputTrafficField = 0) || ($this->inputTrafficField = 0 && $this->outputTrafficField > 0)) " ; } elseif ($duration == "nomedia") { $where .= " and ($this->inputTrafficField = 0 && $this->outputTrafficField = 0) " ; } $this->url.=sprintf("&duration=%s", urlencode($duration)); } if ($media_info) { $this->url.=sprintf("&media_info=%s", urlencode($media_info)); $where .= sprintf(" and %s = '%s' ", addslashes($this->MediaInfoField), addslashes($media_info)); } $this->url.=sprintf("&maxrowsperpage=%s", addslashes($this->maxrowsperpage)); $url_calls = $this->scriptFile.$this->url."&action=search"; if ($group_by) { $this->url.=sprintf("&group_by=%s", urlencode($group_by)); } $this->url_edit = $this->scriptFile.$this->url."&action=edit"; $this->url_run = $this->scriptFile.$this->url."&action=search"; $this->url_export = $_SERVER["PHP_SELF"].$this->url."&action=search&export=1"; if ($duration == "unnormalized") { $where .= " and $this->normalizedField = '0' "; } if ($duration == "unnormalized_duration") { $where .= " and $this->normalizedField = '0' and $this->durationField > 0 "; } if ($group_by) { $this->group_byOrig=$group_by; if ($group_by=="hour") { $group_by="HOUR(AcctStartTime)"; } elseif (preg_match("/^DAY/", $group_by)) { $group_by="$group_by(AcctStartTime)"; } elseif (preg_match("/BYMONTH/", $group_by)) { $group_by="DATE_FORMAT(AcctStartTime,'%Y-%m')"; } elseif (preg_match("/BYYEAR/", $group_by)) { $group_by="DATE_FORMAT(AcctStartTime,'%Y')"; } elseif ($group_by=="UserAgentType") { $group_by="SUBSTRING_INDEX($this->SipUserAgentsField, ' ', '1')"; } $this->group_by=$group_by; if ($group_by==$this->callIdField) { $having = sprintf(" having count(%s) > 1 ", addslashes($group_by)); } $query= sprintf( " select sum(%s) as duration, SEC_TO_TIME(sum(%s)) as duration_print, count(%s) as calls, %s from %s where %s group by %s %s ", addslashes($this->durationField), addslashes($this->durationField), $group_by, $group_by, addslashes($cdr_table), $where, $group_by, $having ); } else { $query = sprintf("select count(*) as records from %s where ", addslashes($cdr_table)). $where; } dprint_sql($query); if ($this->CDRdb->query($query)) { $this->CDRdb->next_record(); if ($group_by) { $rows = $this->CDRdb->num_rows(); } else { $rows = $this->CDRdb->f('records'); } } else { printf("%s", $this->CDRdb->Error); $rows = 0; } $this->rows=$rows; if ($this->CDRTool['filter']['aNumber']) { $this->showResultsMenuSubscriber('0', $begin_datetime, $end_datetime); } else { $this->showResultsMenu('0', $begin_datetime, $end_datetime); } if (!$this->next) { $i=0; $this->next=0; } else { $i = intval($this->next); } $j=0; $z=0; if ($rows > 0) { if ($call_id && $ReNormalize) { $query = sprintf( " update %s set %s = '0' where %s = '%s' ", addslashes($cdr_table), addslashes($this->normalizedField), addslashes($this->callIdField), addslashes($call_id) ); $this->CDRdb->query($query); } if ($UnNormalizedCalls = $this->getUnNormalized($where, $cdr_table)) { if (!$this->DATASOURCES[$this->cdr_source]['skipNormalizeOnPageLoad']) { if ($UnNormalizedCalls < $this->maxCDRsNormalizeWeb) { $this->NormalizeCDRS($where, $cdr_table); if (!$this->export && $this->status['normalized']) { print "
"; print "  "; printf("%d CDRs normalized. ", $this->status['normalized']); if ($this->status['cached_keys']['saved_keys']) { printf("Quota usage updated for %d accounts. ", $this->status['cached_keys']['saved_keys']); } print "
"; } } } } if ($rows > $this->maxrowsperpage) { $maxrows = $this->maxrowsperpage + $this->next; if ($maxrows > $rows) { $maxrows = $rows; $prev_rows = $maxrows; } } else { $maxrows = $rows; } if ($duration == "unnormalized") { // if display un normalized calls we must substract // the amount of calls normalized above $maxrows=$maxrows-$this->status['normalized']; } if ($group_by) { if ($order_by == "group_by") { $order_by1 = $group_by; } else { if ($order_by == $this->inputTrafficField || $order_by == $this->outputTrafficField || $order_by == $this->durationField || $order_by == $this->priceField || $order_by == "zeroP" || $order_by == "nonzeroP" ) { $order_by1 = $order_by; } else { $order_by1 = "calls"; } } $this->SipMethodField = $this->CDRFields['SipMethod']; $query = " select sum($this->durationField) as $this->durationField, SEC_TO_TIME(sum($this->durationField)) as hours, count($group_by) as calls, $this->SipMethodField, 2*sum($this->inputTrafficField)/1024/1024 as $this->inputTrafficField, 2*sum($this->outputTrafficField)/1024/1024 as $this->outputTrafficField, SUM($this->durationField = '0') as zero, SUM($this->durationField > '0') as nonzero,"; if ($order_by=="zeroP" || $order_by=="nonzeroP") { $query .= " SUM($this->durationField = '0')/count($group_by)*100 as zeroP, SUM($this->durationField > '0')/count($group_by)*100 as nonzeroP,"; } $query .= " sum($this->inputTrafficField)*8*2/1024/sum($this->durationField) as netrate_in, sum($this->outputTrafficField)*8*2/1024/sum($this->durationField) as netrate_out"; if ($this->priceField) { $query .= ", sum($this->priceField) as $this->priceField "; } $_max_rows = intval($this->maxrowsperpage); if (!$_max_rows) { $_max_rows = 10; } /* $query.= " , $group_by as mygroup from $cdr_table where $where group by $group_by $having order by $order_by1 $order_type limit $i,$_max_rows "; */ $query.= sprintf( " , %s as mygroup from %s where %s group by %s %s order by %s %s limit %d, %d ", $group_by, addslashes($cdr_table), $where, $group_by, addslashes($having), addslashes($order_by1), addslashes($order_type), $i, $_max_rows ); dprint_sql($query); $this->CDRdb->query($query); $this->showTableHeaderStatistics(); while ($i<$maxrows) { $found = $i + 1; $this->CDRdb->next_record(); $calls = $this->CDRdb->f('calls'); $seconds = $this->CDRdb->f($this->durationField); $seconds = $this->CDRdb->f($this->durationField); $seconds_print = number_format($this->CDRdb->f($this->durationField), 0); $minutes = number_format($this->CDRdb->f($this->durationField)/60, 0, "", ""); $minutes_print = number_format($this->CDRdb->f($this->durationField)/60, 0); $hours = $this->CDRdb->f('hours'); $AcctInputOctets = number_format($this->CDRdb->f($this->inputTrafficField), 2, ".", ""); $AcctOutputOctets = number_format($this->CDRdb->f($this->outputTrafficField), 2, ".", ""); $NetRateIn = $this->CDRdb->f('netrate_in'); $NetRateOut = $this->CDRdb->f('netrate_out'); $SipMethod = $this->CDRdb->f($this->callTypeField); $AcctTerminateCause = $this->CDRdb->f($this->disconnectField); $mygroup = $this->CDRdb->f('mygroup'); $zero = $this->CDRdb->f('zero'); $nonzero = $this->CDRdb->f('nonzero'); $success = number_format($nonzero/$calls*100, 2, ".", ""); $failure = number_format($zero/$calls*100, 2, ".", ""); $NetworkRateIn = number_format($NetRateIn, 2); $NetworkRateOut = number_format($NetRateOut, 2); $NetworkRate = max($NetworkRateIn, $NetworkRateOut); if ($this->priceField) { $price = $this->CDRdb->f($this->priceField); } $rr = floor($found/2); $mod=$found-$rr*2; if ($mod ==0) { $inout_color="lightgrey"; } else { $inout_color="white"; } $traceValue=""; $mygroup_print = quoted_printable_decode($mygroup); if ($this->group_byOrig==$this->DestinationIdField) { if ($this->CDRTool['filter']['domain'] && $this->destinations[$this->CDRTool['filter']['domain']]) { list($_dst_id, $_dst_name) = $this->getPSTNDestinationId($mygroup, '', $this->CDRTool['filter']['domain']); $description=$_dst_name; } else { $description=$this->destinations[0]["default"][$mygroup]["name"]; //list($_dst_id,$_dst_name)=$this->getPSTNDestinationId($mygroup); //$description=$_dst_name; } if ($mygroup) { $traceValue=$mygroup; } else { $traceValue="empty"; } } elseif ($this->group_byOrig==$this->aNumberField) { // Normalize Called Station Id $N=$this->NormalizeNumber($mygroup); $mygroup_print=$N['username']."@".$N[domain]; $description=""; $traceField="a_number"; $traceValue = urlencode($mygroup); } elseif ($this->group_byOrig==$this->CanonicalURIField) { $traceField="c_number"; $traceValue = urlencode($mygroup); } elseif ($this->group_byOrig==$this->SipProxyServerField) { $traceField="sip_proxy"; $traceValue = urlencode($mygroup); } elseif ($this->group_byOrig==$this->MediaRelayField) { $traceField="media_relay"; $traceValue = urlencode($mygroup); } elseif ($this->group_byOrig==$this->SipCodecField) { $traceField="SipCodec"; } elseif (preg_match("/UserAgent/", $this->group_byOrig)) { $traceField="UserAgent"; } elseif (preg_match("/^BY/", $this->group_byOrig)) { $traceField="MONTHYEAR"; } elseif ($this->group_byOrig==$this->callIdField) { $traceField="call_id"; } elseif ($this->group_byOrig=="DAYOFWEEK") { if ($mygroup == "1") { $description="Sunday"; } elseif ($mygroup == "2") { $description="Monday"; } elseif ($mygroup == "3") { $description="Tuesday"; } elseif ($mygroup == "4") { $description="Wednesday"; } elseif ($mygroup == "5") { $description="Thursday"; } elseif ($mygroup == "6") { $description="Friday"; } elseif ($mygroup == "7") { $description="Saturday"; } } elseif ($this->group_byOrig=="DAYOFMONTH") { $description =$this->CDRdb->f('day'); } elseif ($this->group_byOrig=="DAYOFYEAR") { $description =$this->CDRdb->f('day'); } elseif ($this->group_byOrig=="SourceIP") { $traceField="gateway"; } elseif ($this->group_byOrig=="SipResponseCode") { $description =$this->disconnectCodesDescription[$mygroup]; $traceField="sip_status"; } elseif ($this->group_byOrig=="SipApplicationType") { $traceField="application"; } elseif ($this->group_byOrig=="ServiceType") { $traceField="flow"; } else { $description=""; } if (!$traceField) { $traceField = $group_by; } if (!$traceValue) { $traceValue = $mygroup; } if (!$traceValue) { $traceValue=""; $comp_type="empty"; } else { $comp_type="begin"; } $traceValue_enc = urlencode($traceValue); if (!$this->export) { print " $found $calls $seconds_print $minutes_print $hours "; if ($perm->have_perm("showPrice")) { $pricePrint = number_format($price, 4, ".", ""); } else { $pricePrint = 'x.xxx'; } print " $pricePrint $AcctInputOctets $AcctOutputOctets $success% ($nonzero calls) $failure% ($zero calls) $mygroup_print $description "; printf( "Display calls", $url_calls, $traceField, $traceValue_enc, $traceField, $comp_type ); print ""; } else { print "$found,"; print "$calls,"; print "$seconds,"; print "$minutes,"; print "$hours,"; if ($perm->have_perm("showPrice")) { $pricePrint=$price; } else { $pricePrint='x.xxx'; } print "$pricePrint,"; print "$AcctInputOctets,"; print "$AcctOutputOctets,"; print "$success,"; print "$nonzero,"; print "$failure,"; print "$zero,"; print "$mygroup_print,"; print "$description"; print "\n"; } $i++; } if (!$this->export) { print ""; } } else { if (!$this->export) { // printf ("
For more information about each call click on its Id column.
"); } if ($order_by=="zeroP" || $order_by=="nonzeroP") { $order_by="timestamp"; } $_max_rows = intval($this->maxrowsperpage); if (!$_max_rows) { $_max_rows = 10; } $query = sprintf( "select *, UNIX_TIMESTAMP($this->startTimeField) as timestamp from %s where %s order by %s %s limit %d, %d", addslashes($cdr_table), $where, addslashes($order_by), addslashes($order_type), intval($i), $_max_rows ); $this->CDRdb->query($query); if ($this->CDRTool['filter']['aNumber']) { $this->showTableHeaderSubscriber(); } else { if (!$this->export) { $this->showTableHeader(); } else { $this->showExportHeader(); } } while ($i<$maxrows) { global $found; $found = $i + 1; $this->CDRdb->next_record(); $Structure=$this->_readCDRFieldsFromDB(''); //dprint_r($Structure); $CDR = new $this->CDR_class($this, $Structure); if ($this->CDRTool['filter']['aNumber']) { $CDR->showSubscriber(); } else { if (!$this->export) { $CDR->show(); } else { $CDR->export(); } } $i++; } if (!$this->export) { print ""; } } $this->showPagination($this->next, $maxrows); } } function LoadDomains() { if (!$this->db_subscribers) { $log = printf("Error: Cannot load domains because db_subscribers is not defined in datasource %s", $this->cdr_source); print $log; syslog(LOG_NOTICE, $log); return false; } if (!is_object($this->AccountsDB)) { $log = printf("Error: AccountsDB is not a valid database object"); print $log; syslog(LOG_NOTICE, $log); return false; } if (strlen($this->DATASOURCES[$this->cdr_source]['enableThor'])) { $this->domain_table = "sip_domains"; } else { $this->domain_table = "domain"; } $query = sprintf("select * from %s", $this->domain_table); if ($this->CDRTool['filter']['aNumber']) { $els = explode("@", $this->CDRTool['filter']['aNumber']); $query.= sprintf(" where domain = '%s' ", addslashes($els[1])); } elseif ($this->CDRTool['filter']['domain']) { $fdomain = $this->CDRTool['filter']['domain']; $query.=sprintf(" where domain = '%s' ", addslashes($fdomain)); } if (!$this->AccountsDB->query($query)) { $log=sprintf("Database %s error: %s (%d) %s\n", $this->db_subscribers, $this->AccountsDB->Error, $this->AccountsDB->Errno, $query); print $log; syslog(LOG_NOTICE, $log); return false; } while ($this->AccountsDB->next_record()) { if ($this->AccountsDB->f('domain')) { $this->localDomains[$this->AccountsDB->f('domain')] = array( 'name' => $this->AccountsDB->f('domain'), 'reseller' => intval($this->AccountsDB->f('reseller_id')) ); } } return count($this->localDomains); } function LoadTrustedPeers() { if (!$this->db_subscribers) { $log=printf("Error: Cannot load trusted peers because db_subscribers is not defined in datasource %s", $this->cdr_source); print $log; syslog(LOG_NOTICE, $log); return false; } if (!is_object($this->AccountsDB)) { $log = printf("Error: AccountsDB is not a valid database object"); print $log; syslog(LOG_NOTICE, $log); return false; } if (strlen($this->DATASOURCES[$this->cdr_source]['enableThor'])) { $this->trusted_table = "sip_trusted"; } else { $this->trusted_table = "trusted_peers"; } $query=sprintf("select * from %s", addslashes($this->trusted_table)); if (!$this->AccountsDB->query($query)) { $log = sprintf("Database %s error: %s (%d) %s\n", $this->db_subscribers, $this->AccountsDB->Error, $this->AccountsDB->Errno, $query); print $log; syslog(LOG_NOTICE, $log); return false; } while ($this->AccountsDB->next_record()) { if ($this->AccountsDB->f('ip')) { $this->trustedPeers[$this->AccountsDB->f('ip')] = array( 'ip' => $this->AccountsDB->f('ip'), 'reseller' => intval($this->AccountsDB->f('reseller_id')) ); } } return count($this->trustedPeers); } function getQuota($account) { if (!$this->quotaEnabled) { return true; } if (!$account) { return; } if (!is_object($this->AccountsDB)) { $log = printf("Error: AccountsDB is not a valid database object"); print $log; syslog(LOG_NOTICE, $log); return false; } list($username, $domain) = explode("@", $account); if ($this->enableThor) { $query = sprintf("select * from sip_accounts where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain)); if (!$this->AccountsDB->query($query)) { $log = sprintf("Database error for query 1 %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno); syslog(LOG_NOTICE, $log); return 0; } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); $_profile=json_decode(trim($this->AccountsDB->f('profile'))); return $_profile->quota; } else { return 0; } } else { $query=sprintf("select quota from subscriber where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain)); if (!$this->AccountsDB->query($query)) { $log=sprintf("Database error for query %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno); syslog(LOG_NOTICE, $log); return 0; } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); return $this->AccountsDB->f('quota'); } else { return 0; } } } function getBlockedByQuotaStatus($account) { if (!$this->quotaEnabled) { return true; } if (!$account) { return 0; } if (!is_object($this->AccountsDB)) { $log=printf("Error: AccountsDB is not a valid database object"); print $log; syslog(LOG_NOTICE, $log); return false; } list($username, $domain) = explode("@", $account); if ($this->enableThor) { $query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain)); if (!$this->AccountsDB->query($query)) { $log = sprintf("Database error for query2 %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno); syslog(LOG_NOTICE, $log); return 0; } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); $_profile=json_decode(trim($this->AccountsDB->f('profile'))); if (in_array('quota', $_profile->groups)) { return 1; } else { return 0; } } else { return 0; } } else { $query=sprintf("select CONCAT(username,'@',domain) as account from grp where grp = 'quota' and username = '%s' and domain = '%s'", addslashes($username), addslashes($domain)); if (!$this->AccountsDB->query($query)) { $log = sprintf("Database error for query %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno); syslog(LOG_NOTICE, $log); return 0; } if ($this->AccountsDB->num_rows()) { return 1; } else { return 0; } } return 0; } function notifyLastSessions($count='200', $account='') { // send emails with last missed and received sessions to subscribers in group $this->missed_calls_group $lockName = sprintf("%s:notifySessions", $this->cdr_source); if (!$this->getNormalizeLock($lockName)) { return true; } if (strlen($account)) { list($username, $domain) = explode('@', $account); if (!strlen($username) || !strlen($domain)) { return false; } } else { $query=sprintf("select * from memcache where `key` = '%s'", 'notifySessionsLastRun'); $this->cdrtool->query($query); if ($this->cdrtool->num_rows()) { $this->cdrtool->next_record(); $lastRun=$this->cdrtool->f('value'); if (Date('Y-m-d') == $lastRun) { $log=sprintf("Notify sessions script already run for date %s\n", $lastRun); print $log; syslog(LOG_NOTICE, $log); return true; } } } $this->notifySubscribers=array(); require_once('Mail.php'); require_once('Mail/mime.php'); if ($this->enableThor) { $query=sprintf("select * from sip_accounts"); if (strlen($account)) { $query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain)); } if (!$this->AccountsDB->query($query)) { $log=sprintf("Database error for query %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno); syslog(LOG_NOTICE, $log); return 0; } if ($this->AccountsDB->num_rows()) { while ($this->AccountsDB->next_record()) { $_profile=json_decode(trim($this->AccountsDB->f('profile'))); if (in_array($this->missed_calls_group, $_profile->groups)) { $this->notifySubscribers[$this->AccountsDB->f('username').'@'.$this->AccountsDB->f('domain')]=array('email'=>$this->AccountsDB->f('email'),'timezone' => $_profile->timezone); } } } else { return 0; } } else { $query = sprintf( "select CONCAT(username,'@',domain) as account,email_address,timezone from grp join subscriber on grp.subscriber_id =subscriber.id where grp = '%s'", addslashes($this->missed_calls_group) ); if (strlen($account)) { $query.= sprintf(" and username = '%s' and domain = '%s' ", $username, $domain); } if (!$this->AccountsDB->query($query)) { $log = sprintf("Database error for query %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno); syslog(LOG_NOTICE, $log); return 0; } if ($this->AccountsDB->num_rows()) { while ($this->AccountsDB->next_record()) { $this->notifySubscribers[$this->AccountsDB->f('account')]=array('email'=>$this->AccountsDB->f('email_address'),'timezone' => $this->AccountsDB->f('timezone')); } } else { return 0; } } if (!count($this->notifySubscribers)) { return 0; } $j = 0; foreach (array_keys($this->notifySubscribers) as $_subscriber) { $j++; $_last_sessions=array(); unset($textBody); unset($htmlBody); $query = sprintf( " SELECT *, UNIX_TIMESTAMP(%s) as timestamp FROM %s where (%s = '%s' or %s = '%s') and %s > DATE_ADD(NOW(), INTERVAL -1 day) order by %s desc limit 200", addslashes($this->startTimeField), addslashes($this->table), addslashes($this->usernameField), addslashes($_subscriber), addslashes($this->CanonicalURIField), addslashes($_subscriber), addslashes($this->startTimeField), addslashes($this->startTimeField) ); if (!$this->CDRdb->query($query)) { $log = sprintf("Database error for query %s: %s (%s)", $query, $this->CDRdb->Error, $this->CDRdb->Errno); syslog(LOG_NOTICE, $log); print $log; return 0; } if (Date('d') == 1) { while ($this->CDRdb->next_record()) { $_last_sessions[] = array( 'duration' => $this->CDRdb->f($this->durationField), 'from' => $this->CDRdb->f($this->aNumberField), 'to' => $this->CDRdb->f($this->cNumberField), 'username' => $this->CDRdb->f($this->usernameField), 'canonical' => $this->CDRdb->f($this->CanonicalURIField), 'date' => getlocaltime($this->notifySubscribers[$_subscriber]['timezone'], $this->CDRdb->f('timestamp')) ); } if (preg_match("/^(\w+)(\d{4})(\d{2})$/", $this->table, $m)) { $previousTable=$m[1].date('Ym', mktime(0, 0, 0, $m[3]-1, "01", $m[2])); $query = sprintf( " SELECT *, UNIX_TIMESTAMP(%s) as timestamp FROM %s where %s = '%s' and %s > DATE_ADD(NOW(), INTERVAL -1 day) order by %s desc limit 200 ", addslashes($this->startTimeField), addslashes($previousTable), addslashes($this->CanonicalURIField), addslashes($_subscriber), addslashes($this->startTimeField), addslashes($this->startTimeField) ); if (!$this->CDRdb->query($query)) { $log = sprintf("Database error for query %s: %s (%s)", $query, $this->CDRdb->Error, $this->CDRdb->Errno); syslog(LOG_NOTICE, $log); print $log; return 0; } while ($this->CDRdb->next_record()) { $_last_sessions[] = array( 'duration' => $this->CDRdb->f($this->durationField), 'from' => $this->CDRdb->f($this->aNumberField), 'to' => $this->CDRdb->f($this->cNumberField), 'username' => $this->CDRdb->f($this->usernameField), 'canonical' => $this->CDRdb->f($this->CanonicalURIField), 'date' => getlocaltime($this->notifySubscribers[$_subscriber]['timezone'], $this->CDRdb->f('timestamp')) ); } } } else { while ($this->CDRdb->next_record()) { $_last_sessions[] = array( 'duration' => $this->CDRdb->f($this->durationField), 'from' => $this->CDRdb->f($this->aNumberField), 'to' => $this->CDRdb->f($this->cNumberField), 'username' => $this->CDRdb->f($this->usernameField), 'canonical' => $this->CDRdb->f($this->CanonicalURIField), 'date' => getlocaltime($this->notifySubscribers[$_subscriber]['timezone'], $this->CDRdb->f('timestamp')) ); } } if (!count($_last_sessions)) { continue; } $sessions=array( 'missed' => array(), 'received' => array(), 'diverted' => array() ); $have_sessions=0; foreach ($_last_sessions as $_s) { if ($_s['duration'] == 0 && $_s['canonical'] == $_subscriber) { $sessions['missed'][]=$_s; $have_sessions++; continue; } if ($_s['duration'] > 0 && $_s['canonical'] == $_subscriber) { $sessions['received'][]=$_s; $have_sessions++; continue; } if ($_s['from'] != $_subscriber && $_s['canonical'] != $_subscriber) { $sessions['diverted'][]=$_s; $have_sessions++; continue; } } if (!$have_sessions) { continue; } if (count($sessions['missed'])) { // missed sessions $textBody .= sprintf( " Missed sessions\n\n Id,Date,From,Duration\n " ); $htmlBody .= sprintf("

Missed Calls

"); $i=0; foreach ($sessions['missed'] as $_session) { $i++; if ($i >= $count) { break; } $htmlBody .= sprintf( " ", $i, $_session['date'], $_session['from'], $_session['from'] ); $txtBody.=sprintf( "%s,%s,%s,%s,%s\n", $i, $_session['date'], $_session['from'], $_session['to'] ); } $htmlBody.="
Date and Time Caller
%s %s sip:%s
"; } if (count($sessions['diverted'])) { // diverted sessions $textBody .= sprintf("Diverted Calls\n\n Id,Date,From,Diverted to\n "); $htmlBody .= sprintf("

Diverted Calls

"); $i=0; foreach ($sessions['diverted'] as $_session) { $i++; if ($i >= $count) break; $htmlBody.=sprintf( " ", $i, $_session['date'], $_session['from'], $_session['from'], $_session['canonical'] ); $txtBody .= sprintf( "%s,%s,%s,%s\n", $i, $_session['date'], $_session['from'], $_session['canonical'] ); } $htmlBody.="
Date and Time Caller Diverted to
%s %s sip:%s %s
"; } if (count($sessions['received'])) { // received sessions $textBody .= sprintf("Received Calls\n\nId,Date,From,Duration\n"); $htmlBody .= sprintf( "

Received Calls

" ); $i=1; foreach ($sessions['received'] as $_session) { if ($i >= $count) { break; } $htmlBody .= sprintf( "", $i, $_session['date'], $_session['from'], $_session['from'], $_session['duration'] ); $txtBody .= sprintf( "%s,%s,%s,%s\n", $i, $_session['date'], $_session['from'], $_session['duration'] ); $i++; } $htmlBody.="
Date and Time Caller Duration
%s%ssip:%s%s
"; } $htmlBody.="

This is an automatically generated message, do not reply."; $txtBody.="\nThis is an automatically generated message, do not reply.\n"; $crlf = "\n"; $hdrs = array( 'From'=> $this->CDRTool['provider']['fromEmail'], 'Subject' => sprintf("Incoming Calls for %s on %s", $_subscriber, date('Y-m-d')) ); $mime = new Mail_mime($crlf); $mime->setTXTBody($textBody); $mime->setHTMLBody($htmlBody); $body = $mime->get(); $hdrs = $mime->headers($hdrs); $mail =& Mail::factory('mail'); $mail->send($this->notifySubscribers[$_subscriber]['email'], $hdrs, $body); $log=sprintf( "Notify %s at %s with last %d sessions\n", $_subscriber, $this->notifySubscribers[$_subscriber]['email'], count($_last_sessions) ); print $log; syslog(LOG_NOTICE, $log); } $query = sprintf("update memcache set `value` = '%s' where `key` = '%s'", Date('Y-m-d'), 'notifySessionsLastRun'); if (!$this->cdrtool->query($query)) { $log = sprintf("Database error for query %s: %s (%s)", $query, $this->cdrtool->Error, $this->cdrtool->Errno); print $log; syslog(LOG_NOTICE, $log); return false; } if (!$this->cdrtool->affected_rows()) { $query=sprintf("insert into memcache (`value`,`key`) values ('%s','%s')", Date('Y-m-d'), 'notifySessionsLastRun'); if (!$this->cdrtool->query($query)) { if ($this->cdrtool->Errno != 1062) { $log=sprintf("Database error for query %s: %s (%s)", $query, $this->cdrtool->Error, $this->cdrtool->Errno); print $log; syslog(LOG_NOTICE, $log); return false; } } } } function getCallerId($account) { if (!$account) { return null; } if ($this->callerid_cache[$account]) { return $this->callerid_cache[$account]; } list($username, $domain) = explode('@', $account); if ($this->enableThor) { $query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain)); if (!$this->AccountsDB->query($query)) { $log=sprintf("Database error for query %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno); syslog(LOG_NOTICE, $log); return null; } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); $_profile=json_decode(trim($this->AccountsDB->f('profile'))); $this->callerid_cache[$account]=$_profile->rpid; return $_profile->rpid; } } else { $query=sprintf("select rpid from subscriber where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain)); if (!$this->AccountsDB->query($query)) { $log=sprintf("Database error for query %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno); syslog(LOG_NOTICE, $log); return null; } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); $rpid = $this->AccountsDB->f('rpid'); $this->callerid_cache[$account]=$rpid; return $rpid; } } return null; } function rate_on_net_enabled($username, $domain) { if ($this->enableThor) { $query=sprintf("select * from sip_accounts where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain)); if (!$this->AccountsDB->query($query)) { $log=sprintf("Database error for query %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno); syslog(LOG_NOTICE, $log); return false; } if ($this->AccountsDB->num_rows()) { while ($this->AccountsDB->next_record()) { $_profile = json_decode(trim($this->AccountsDB->f('profile'))); if (in_array($this->rate_on_net_group, $_profile->groups)) { return true; } } } } return false; } } class CDR_opensips extends CDR { function CDR_opensips($parent, $CDRfields) { $this->CDRS = $parent; $this->cdr_source = $this->CDRS->cdr_source; foreach (array_keys($this->CDRS->CDRFields) as $field) { $this->$field = $CDRfields[$this->CDRS->CDRFields[$field]]; } if ($this->CanonicalURI) { $this->CanonicalURI = quoted_printable_decode($this->CanonicalURI); } if ($this->RemoteAddress) { $this->RemoteAddress = quoted_printable_decode($this->RemoteAddress); } if ($this->BillingPartyId) { $this->BillingPartyId = quoted_printable_decode($this->BillingPartyId); } if ($this->aNumber) { $this->aNumber = quoted_printable_decode($this->aNumber); } if ($this->cNumber) { $this->cNumber = quoted_printable_decode($this->cNumber); } if ($this->SipRPID) { $this->SipRPID = quoted_printable_decode($this->SipRPID); } - $this->buildMongoCDR(); - if (!$this->application && $this->SipMethod) { $_method=strtolower($this->SipMethod); if ($_method == 'message') { $this->application = 'message'; $this->stopTimeNormalized=$this->startTime; } else { $this->application = 'audio'; } } if ($this->application == 'message') { $this->stopTimeNormalized=$this->startTime; } $this->application=strtolower($this->application); $this->application_print=quoted_printable_decode($this->application); $this->FromHeaderPrint = quoted_printable_decode($this->FromHeader); if (strstr($this->FromHeaderPrint, ';')) { $_els=explode(";", $this->FromHeaderPrint); $this->FromHeaderPrint = $_els[0]; } $this->FromHeaderPrint = htmlentities($this->FromHeaderPrint); $this->UserAgentPrint = quoted_printable_decode($this->UserAgent); $app_prefix = preg_replace('/[.].*$/', '', $this->application); if (!in_array($app_prefix, $this->supportedApplicationTypes)) { $log=sprintf("Changing application from %s to %s\n", $this->application, $this->defaultApplicationType); syslog(LOG_NOTICE, $log); $this->application = $this->defaultApplicationType; } //$this->applicationNormalized=$this->application; if ($this->aNumber) { $NormalizedNumber = $this->CDRS->NormalizeNumber($this->aNumber, "source"); $this->aNumberPrint = $NormalizedNumber['NumberPrint']; $this->aNumberNormalized = $NormalizedNumber['Normalized']; $this->aNumberUsername = $NormalizedNumber['username']; $this->aNumberDomain = $NormalizedNumber['domain']; } if (!$this->BillingPartyId || $this->BillingPartyId == 'n/a') { $this->BillingPartyId=$this->aNumberPrint; } $this->ResellerId=0; // calculate reseller $_billing_party_els=explode("@", $this->BillingPartyId); if ($this->isBillingPartyLocal()) { $this->ResellerId = $this->CDRS->localDomains[$_billing_party_els[1]]['reseller']; } else { if (!strlen($_billing_party_els[0])) { $this->BillingPartyId=$_billing_party_els[1]; } if (count($_billing_party_els) == 2) { if (!$this->domain) { $this->domain=$_billing_party_els[1]; } if ($this->CDRS->localDomains[$_billing_party_els[1]]['reseller']) { $this->ResellerId = $this->CDRS->localDomains[$_billing_party_els[1]]['reseller']; } elseif ($this->CDRS->trustedPeers[$_billing_party_els[1]]['reseller']) { $this->ResellerId = $this->CDRS->trustedPeers[$_billing_party_els[1]]['reseller']; } } elseif (count($_billing_party_els)==1) { $this->ResellerId=$this->CDRS->trustedPeers[$_billing_party_els[0]]['reseller']; } } if (!strlen($this->ResellerId)) { $this->ResellerId = 0; } $this->BillingPartyId=strtolower($this->BillingPartyId); $this->BillingPartyIdPrint = $this->BillingPartyId; $this->domainNormalized = $this->domain; if (is_array($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation_SourceIP']) && isset($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation_SourceIP'][$this->SourceIP]) && strlen($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation_SourceIP'][$this->SourceIP]) ) { $this->domainNormalized=$this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation_SourceIP'][$this->SourceIP]; } elseif (is_array($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation']) && isset($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation'][$this->domain]) && strlen($this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation'][$this->domain]) ) { $this->domainNormalized=$this->CDRS->DATASOURCES[$this->cdr_source]['domainTranslation'][$this->domain]; } $this->domainNormalized=strtolower($this->domainNormalized); $this->RemoteAddressPrint=quoted_printable_decode($this->RemoteAddress); $_timestamp_stop=$this->timestamp+$this->duration; $this->dayofweek = date("w", $this->timestamp); $this->hourofday = date("G", $this->timestamp); $this->dayofyear = date("Y-m-d", $this->timestamp); // Called Station ID or cNumber should not be used for rating purposes because // it is chosen by the subscriber but the Proxy rewrites it into a different // final destination (the Canonical URI) // Canonical URI is the final logical SIP destination after all // lookups like aliases, usrloc , call forwarding, ENUM // mappings or PSTN gateways but before the DNS lookup // Canonical URI must be saved in the SIP Proxy and added as an extra // Radius attribute in the Radius START packet if (!$this->CanonicalURI) { if ($this->RemoteAddress) { $this->CanonicalURI=$this->RemoteAddress; } elseif ($this->cNumber) { $this->CanonicalURI=$this->cNumber; } } if ($this->CanonicalURI) { $this->CanonicalURIPrint = $this->CanonicalURI; $NormalizedNumber = $this->CDRS->NormalizeNumber( $this->CanonicalURI, "destination", $this->BillingPartyId, $this->domain, $this->gateway, '', $this->ENUMtld, $this->ResellerId ); $this->CanonicalURINormalized = $NormalizedNumber['Normalized']; $this->CanonicalURIUsername = $NormalizedNumber['username']; $this->CanonicalURIDomain = $NormalizedNumber['domain']; $this->CanonicalURIPrint = $NormalizedNumber['NumberPrint']; $this->CanonicalURIDelimiter = $NormalizedNumber['delimiter']; $this->CanonicalURIE164 = $NormalizedNumber['E164']; // Destination Id is used for rating purposes $this->DestinationId = $NormalizedNumber['DestinationId']; $this->destinationName = $NormalizedNumber['destinationName']; $this->region = $NormalizedNumber['region']; } if ($this->cNumber) { $NormalizedNumber = $this->CDRS->NormalizeNumber( $this->cNumber, "destination", $this->BillingPartyId, $this->domain, $this->gateway, '', $this->ENUMtld, $this->ResellerId ); $this->cNumberNormalized = $NormalizedNumber['Normalized']; $this->cNumberUsername = $NormalizedNumber['username']; $this->cNumberDomain = $NormalizedNumber['domain']; $this->cNumberPrint = $NormalizedNumber['username'].$NormalizedNumber['delimiter'].$NormalizedNumber['domain']; $this->cNumberDelimiter = $NormalizedNumber['delimiter']; $this->cNumberE164 = $NormalizedNumber['E164']; } if ($this->RemoteAddress) { // Next hop is the real destination after all lookups including DNS $NormalizedNumber = $this->CDRS->NormalizeNumber( $this->RemoteAddress, "destination", $this->BillingPartyId, $this->domain, $this->gateway, '', $this->ENUMtld, $this->ResellerId ); $this->RemoteAddressPrint = $NormalizedNumber['NumberPrint']; $this->RemoteAddressNormalized = $NormalizedNumber['Normalized']; $this->RemoteAddressDestinationId = $NormalizedNumber['DestinationId']; $this->RemoteAddressDestinationName = $NormalizedNumber['destinationName']; $this->RemoteAddressUsername = $NormalizedNumber['username']; $this->RemoteAddressDelimiter = $NormalizedNumber['delimiter']; $this->RemoteAddressE164 = $NormalizedNumber['E164']; $this->remoteGateway = $NormalizedNumber['domain']; $this->remoteUsername = $NormalizedNumber['username']; } $this->isCalleeLocal(); $this->isCallerLocal(); if ($this->CallerIsLocal) { if ($this->aNumberPrint == $this->BillingPartyId) { // call is not diverted if ($this->CalleeIsLocal) { $this->flow = 'on-net'; } else { $this->flow = 'outgoing'; } } else { // call is diverted if ($this->CalleeIsLocal) { $this->flow = 'on-net-diverted-on-net'; } else { $this->flow = 'on-net-diverted-off-net'; } } } else { if ($this->isBillingPartyLocal()) { // call is diverted by local user if ($this->CalleeIsLocal) { $this->flow = 'diverted-on-net'; } else { $this->flow = 'diverted-off-net'; } } elseif ($this->CalleeIsLocal) { $this->flow = 'incoming'; } else { // transit from trusted peer $this->flow = 'transit'; } } if (( $this->flow == 'on-net' || $this->flow == 'diverted-on-net' || $this->flow == 'on-net-diverted-on-net' ) && $this->application == 'audio' && $this->CDRS->rating_settings['rate_on_net_calls'] && $this->CDRS->rate_on_net_enabled($_billing_party_els[0], $_billing_party_els[1]) && !$this->DestinationId && $this->CalleeCallerId ) { $_dest = preg_replace("/^\+(\d+)$/", "00$1", $this->CalleeCallerId); $NormalizedNumber = $this->CDRS->NormalizeNumber( $_dest, "destination", $this->BillingPartyId, $this->domain, $this->gateway, '', $this->ENUMtld, $this->ResellerId ); $this->DestinationId = $NormalizedNumber['DestinationId']; $this->destinationName = $NormalizedNumber['destinationName']; } if ($this->CDRS->rating_settings['rate_on_net_calls'] && $this->CDRS->rating_settings['rate_on_net_diverted_calls'] && ( $this->flow == 'on-net-diverted-off-net' || $this->flow == 'on-net-diverted-on-net' || $this->flow == 'diverted-on-net' || $this->flow == 'diverted-off-net' ) && !$this->normalized && $this->duration != '0' && $this->disconnect == $this->disconnectOrig ) { $query = sprintf( " update %s set AcctStopTime ='%s', Normalized='0', AcctSessionTime='%s', SipResponseCode='200' where AcctSessionId='%s' and SipFromTag='%s' and SipToTag!='%s' and ( ServiceType='on-net' or ServiceType='on-net-diverted-on-net' or ServiceType='diverted-on-net' or ServiceType='incoming') and AcctSessionTime='' ", $this->CDRS->table, $this->stopTime, $this->duration, $this->callId, $this->SipFromTag, $this->SipToTag ); $this->tdb = new DB_radius; dprint_sql($query); $this->tdb->query($query); } if ($this->application == "presence") { $this->destinationPrint = $this->cNumberUsername.$this->cNumberDelimiter.$this->cNumberDomain; $this->DestinationForRating = $this->cNumberNormalized; } else { if (!$this->DestinationId) { if ($this->CanonicalURIDomain) { $this->destinationPrint = $this->CanonicalURIUsername.$this->CanonicalURIDelimiter.$this->CanonicalURIDomain; } else { $this->destinationPrint = $this->cNumberUsername.$this->cNumberDelimiter.$this->cNumberDomain; } if (strstr($this->CanonicalURINormalized, '@')) { $this->DestinationForRating = $this->CanonicalURINormalized; } else { $this->DestinationForRating = $this->RemoteAddressNormalized; } } else { $this->DestinationForRating = $this->CanonicalURINormalized; $this->destinationPrint = $this->CanonicalURIPrint; } } if ($this->inputTraffic) { $this->inputTrafficPrint = number_format($this->inputTraffic/1024, 2); } else { $this->inputTrafficPrint = 0; } if ($this->outputTraffic) { $this->outputTrafficPrint = number_format($this->outputTraffic/1024, 2); } else { $this->outputTrafficPrint = 0; } if (!$CDRfields['skip_fix_prepaid_duration']) { if (!$this->normalized && $this->callId) { // fix the duration of prepaid sessions if the prepaid duration is different than radius calculated duration $query = sprintf( " select duration from prepaid_history where session = '%s' and destination = '%s' order by id desc limit 1 ", addslashes($this->callId), addslashes($this->destinationPrint) // must be synced with maxsession time ); if ($this->CDRS->cdrtool->query($query)) { if ($this->CDRS->cdrtool->num_rows()) { $this->CDRS->cdrtool->next_record(); $this->durationNormalized = $this->CDRS->cdrtool->f('duration'); $this->durationPrint = sec2hms($this->durationNormalized); } else { $this->durationPrint = sec2hms($this->duration); } } else { $log = sprintf("Database error for query %s: %s (%s)", $query, $this->CDRS->cdrtool->Error, $this->CDRS->cdrtool->Errno); syslog(LOG_NOTICE, $log); } } else { $this->durationPrint = sec2hms($this->duration); } } else { $this->durationPrint = sec2hms($this->duration); } if ($this->disconnect) { $this->disconnectPrint = $this->NormalizeDisconnect($this->disconnect); } if ($this->disconnectOrig != $this->disconnect && $this->disconnect && $this->CDRS->rating_settings['rate_on_net_diverted_calls']) { $this->disconnectOrigPrint =$this->CDRS->disconnectCodesDescription[$this->disconnectOrig]." (".$this->disconnectOrig.")"; } $this->traceIn(); $this->traceOut(); $this->obfuscateCallerId(); if ($this->CDRS->rating) { global $perm; if (is_object($perm) && $perm->have_perm("showPrice")) { $this->pricePrint=$this->price; } else { $this->pricePrint='x.xxx'; } } } - function buildMongoCDR() - { - # TODO = remove me - $this->mongo_cdr = array(); - $int_values = array('duration', 'inputTraffic', 'outputTraffic', 'timestamp', 'disconnect'); - foreach (array_keys($this->CDRS->CDRFields) as $field) { - if (in_array($field, $int_values)) { - $this->mongo_cdr[$field] = intval($this->$field); - } else { - $this->mongo_cdr[$field] = $this->$field; - } - } - - if ($this->CanonicalURI) { - $this->mongo_cdr['CanonicalURI'] = $this->CanonicalURI; - } - - if ($this->RemoteAddress) { - $this->mongo_cdr['RemoteAddress'] = $this->RemoteAddress; - } - - if ($this->BillingPartyId) { - $this->mongo_cdr['BillingPartyId'] = $this->BillingPartyId; - } - - if ($this->aNumber) { - $this->mongo_cdr['aNumber'] = $this->aNumber; - } - - if ($this->cNumber) { - $this->mongo_cdr['cNumber'] = $this->cNumber; - } - - if ($this->SipRPID) { - $this->mongo_cdr['SipRPID'] = $this->SipRPID; - } - } - function buildCDRdetail() { global $perm; global $found; if (!is_object($perm)) return; $this->geo_location = $this->lookupGeoLocation($this->SourceIP); $this->cdr_details = "

SIP Signalling
"; $this->cdr_details .= sprintf( "Click here to show only this call id", $this->CDRS->url_run, urlencode($this->callId) ); if ($this->CDRS->sipTrace) { $trace_query = array( 'cdr_source' => $this->CDRS->sipTrace, 'callid' => quoted_printable_decode($this->callId), 'fromtag' => quoted_printable_decode($this->SipFromTag), 'totag' => quoted_printable_decode($this->SipToTag), 'proxyIP' => $this->SipProxyServer ); $this->traceLink = sprintf( " Click here for the SIP trace  ", http_build_query($trace_query) ); $this->cdr_details .= "
Call id:
$this->callId
"; } $this->cdr_details .= sprintf( "
%s
", $this->traceLink ); $this->cdr_details .= "
From tag:
$this->SipFromTag
To tag:
$this->SipToTag
Start Time:
$this->startTime $providerTimezone
Stop Time:
$this->stopTime
"; $this->cdr_details .= sprintf( "
Country:
%s
", $this->geo_location ); $this->cdr_details .= "
Method:
$this->SipMethod from $this->SourceIP:$this->SourcePort
From:
$this->aNumberPrint
From Header:
$this->FromHeaderPrint
User Agent:
$this->UserAgentPrint
Domain:
$this->domain
To (dialed URI):
$this->cNumberPrint
"; if ($this->CanonicalURI) { $this->cdr_details .= sprintf( "
Canonical URI:
%s
", htmlentities($this->CanonicalURI) ); } $this->cdr_details .= sprintf( "
Next Hop URI:
%s
", htmlentities($this->RemoteAddress) ); if ($this->DestinationId) { $this->cdr_details .= "
Destination:
$this->destinationName ($this->DestinationId)
"; } if ($this->ENUMtld && $this->ENUMtld != 'none' && $this->ENUMtld != 'N/A') { $this->cdr_details .= "
ENUM TLD:
$this->ENUMtld
"; } if ($this->SipRPID) { $this->cdr_details .= "
Caller ID:
$this->SipRPIDPrint
"; } if ($this->CalleeCallerId) { $this->cdr_details .= "
Called ID:
$this->CalleeCallerId
"; } $this->cdr_details .= "
Billing Party:
$this->BillingPartyIdPrint
Reseller:
$this->ResellerId
"; $this->cdr_details .= "
"; if ($this->application != 'message') { $this->cdr_details .= "
Media Streams
"; if ($this->CDRS->mediaTrace) { $media_query = array( 'cdr_source' => $this->CDRS->mediaTrace, 'callid' => quoted_printable_decode($this->callId), 'fromtag' => quoted_printable_decode($this->SipFromTag), 'totag' => quoted_printable_decode($this->SipToTag), 'proxyIP' => $this->SipProxyServer ); $this->mediaTraceLink = sprintf( "Click here for media information  ", http_build_query($media_query) ); $this->cdr_details .= sprintf( "
%s
", $this->mediaTraceLink ); } $sessionId = rtrim(base64_encode(hash('md5', $this->callId, true)), "="); $this->cdr_details .= "
Session ID:
$sessionId
"; $this->SipCodec = quoted_printable_decode($this->SipCodec); if ($this->SipCodec) { $this->cdr_details .= "
Codecs:
$this->SipCodec
"; } $this->cdr_details .= "
Caller RTP:
$this->inputTrafficPrint KB
Called RTP:
$this->outputTrafficPrint KB
"; if ($this->MediaInfo) { $this->cdr_details .= "
Media Info:
$this->MediaInfo
"; } $this->cdr_details .= "
Applications:
$this->application_print
"; } if ($this->SipUserAgents) { $this->SipUserAgents = quoted_printable_decode($this->SipUserAgents); $callerAgents = explode("+", $this->SipUserAgents); $callerUA = htmlentities($callerAgents[0]); $calledUA = htmlentities($callerAgents[1]); $this->cdr_details.= "
Caller SIP UA:
$callerUA
Called SIP UA:
$calledUA
"; } $this->cdr_details.= "
"; if ($perm->have_perm("showPrice") && $this->normalized) { $this->cdr_details.= "
Rating
"; if ($this->price > 0 || $this->rate) { $this->ratePrint=nl2br($this->rate); $this->cdr_details.= "
$this->ratePrint
"; } else { $this->cdr_details.= "
Free call
"; } $this->cdr_details.= "
"; } $this->cdr_details.= "
"; } function traceIn() { $datasource=$this->CDRS->traceInURL[$this->SourceIP]; global $DATASOURCES; if (!$datasource || !$DATASOURCES[$datasource]) { return; } $tplus = $this->timestamp+$this->duration+300; $tmin = $this->timestamp-300; $c_number = $this->remoteUsername; $cdr_table = Date('Ym', time($this->timestamp)); $this->traceIn = "". "In". ""; } function traceOut() { $datasource = $this->CDRS->traceOutURL[$this->remoteGateway]; global $DATASOURCES; if (!$datasource || !$DATASOURCES[$datasource]) { return; } $tplus = $this->timestamp+$this->duration+300; $tmin = $this->timestamp-300; $c_number = preg_replace("/^(0+)/", "", $this->remoteUsername); $cdr_table = Date('Ym', time($this->timestamp)); $this->traceOut= "". "Out". ""; } function show() { $this->buildCDRdetail(); global $found; global $perm; $rr = floor($found / 2); $mod = $found - $rr * 2; if ($mod == 0) { $inout_color = "#F9F9F9"; } else { $inout_color = "white"; } $this->ratePrint = nl2br($this->rate); if ($this->CDRS->Accounts[$this->BillingPartyId]['timezone']) { $timezone_print = $this->CDRS->Accounts[$this->BillingPartyId]['timezone']; } else { $timezone_print = $this->CDRS->CDRTool['provider']['timezone']; } $found_print = $found; if ($this->normalized) { $found_print .= 'N'; } $providerTimezone = $this->CDRS->CDRTool['provider']['timezone']; print " $found_print $this->startTime $this->application $this->flow $this->aNumberPrint $this->geo_location $this->SipProxyServer $this->MediaRelay $this->destinationPrint "; if ($this->DestinationId) { if ($this->DestinationId != $this->CanonicalURI) { print " ($this->destinationName $this->DestinationId)"; } else { print " ($this->destinationName)"; } } print ""; if (!$this->normalized) { if ($this->duration > 0) { print "$this->duration(s)"; } else { print "in progress"; } } else { print " $this->durationPrint $this->pricePrint $this->inputTrafficPrint $this->outputTrafficPrint "; } $SIPclass=substr($this->disconnect, 0, 1); if ($SIPclass=="6") { $status_color=""; } elseif ($SIPclass == "5") { $status_color=""; } elseif ($SIPclass == "4") { $status_color=""; } elseif ($SIPclass == "3") { $status_color=""; } elseif ($SIPclass == "2") { $status_color=""; } else { $status_color=""; } if ($this->disconnectOrig != $this->disconnect && $this->CDRS->rating_settings['rate_on_net_diverted_calls']) { $disclass = substr($this->disconnectOrig, 0, 1); if ($disclass == "6" || $disclass == "5") { $status1_color=""; } elseif ($disclass == "4") { $status1_color=""; } elseif ($disclass == "3") { $status1_color=""; } elseif ($disclass == "2") { $status1_color=""; } else { $status1_color=""; } } print " $status_color $this->disconnectPrint"; if ($this->disconnectOrig != $this->disconnect && $this->CDRS->rating_settings['rate_on_net_diverted_calls']) { print "$status1_color $this->disconnectOrigPrint"; } print " $this->cdr_details "; } function export() { global $found; $disconnectName = $this->CDRS->disconnectCodesDescription[$this->disconnect]; $UserAgents = explode("+", $this->SipUserAgents); $CallingUserAgent = trim($UserAgents[0]); $CalledUserAgent = trim($UserAgents[1]); print "$found"; print ",$this->startTime"; print ",$this->stopTime"; print ",$this->BillingPartyIdPrint"; print ",$this->domain"; print ",$this->SipRPIDPrint"; print ",$this->aNumberPrint"; print ",$this->destinationPrint"; print ",$this->DestinationId"; print ",$this->destinationName"; print ",$this->RemoteAddressPrint"; print ",$this->CanonicalURIPrint"; print ",$this->duration"; print ",$this->price"; print ",$this->SipProxyServer"; print ",$this->inputTraffic"; print ",$this->outputTraffic"; printf(",%s", preg_replace("/,/", "/", quoted_printable_decode($CallingUserAgent))); printf(",%s", preg_replace("/,/", "/", quoted_printable_decode($CalledUserAgent))); print ",$this->disconnect"; print ",$disconnectName"; printf(",%s", preg_replace("/,/", "/", quoted_printable_decode($this->SipCodec))); print ",$this->application"; print ",$this->MediaRelay"; print "\n"; } function showSubscriber() { $this->buildCDRdetail(); global $found; $rr=floor($found/2); $mod=$found-$rr*2; if ($mod ==0) { $inout_color="lightgrey"; } else { $inout_color="white"; } if (!$this->CDRS->export) { $timezone_print=$this->CDRS->CDRTool['provider']['timezone']; $found_print=$found; if ($this->normalized) { $found_print.='N'; } print " $found_print $this->startTime $timezone_print $this->aNumberPrint $this->geo_location $this->SipProxyServer $this->destinationPrint $this->destinationName $this->durationPrint "; if ($this->CDRS->rating) { print "$this->pricePrint"; } print " $this->inputTrafficPrint $this->outputTrafficPrint "; print " $this->cdr_details "; } else { $disconnectName = $this->CDRS->disconnectCodesDescription[$this->disconnect]; $UserAgents = explode("+", $this->SipUserAgents); $CallingUserAgent = trim($UserAgents[0]); $CalledUserAgent = trim($UserAgents[1]); print "$found,$this->startTime,$this->stopTime,$this->BillingPartyId,$this->domain,$this->aNumberPrint,$this->cNumberPrint,$this->DestinationId,$this->destinationName,$this->RemoteAddressPrint,$this->duration,$this->price,$this->SipProxyServer,$this->inputTraffic,$this->outputTraffic,$CallingUserAgent,$CalledUserAgent,$this->disconnect,$disconnectName,$this->SipCodec,$this->application\n"; } } function isBillingPartyLocal() { $els = explode("@", $this->BillingPartyId); if ($els[1] && isset($this->CDRS->localDomains[$els[1]])) { return true; } return false; } function isCallerLocal() { if (isset($this->CDRS->localDomains[$this->aNumberDomain])) { $this->CallerIsLocal = true; $this->SipRPID = $this->CDRS->getCallerId($this->BillingPartyId); $this->SipRPIDPrint = $this->SipRPID; #$this->SipRPIDPrint = quoted_printable_decode($this->SipRPID); } } function isCalleeLocal() { if (isset($this->CDRS->localDomains[$this->CanonicalURIDomain]) && !preg_match("/^0/", $this->CanonicalURIUsername)) { $this->CalleeIsLocal = true; $this->CalleeCallerId = $this->CDRS->getCallerId($this->CanonicalURI); } } function obfuscateCallerId() { global $obfuscateCallerId; if ($obfuscateCallerId) { //Caller party $caller_els=explode("@", $this->aNumberPrint); if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) { $_user = substr($caller_els[0], 0, strlen($caller_els[0])-3).'xxx'; } else { $_user = 'caller'; } if (count($caller_els) == 2) { $this->aNumberPrint = $_user.'@'.$caller_els[1]; } else { $this->aNumberPrint = $_user; } //Billing party $caller_els = explode("@", $this->BillingPartyIdPrint); if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) { $_user = substr($caller_els[0], 0, strlen($caller_els[0])-3).'xxx'; } else { $_user = 'party'; } $this->BillingPartyIdPrint = $_user.'@'.$caller_els[1]; // Destination $caller_els = explode("@", $this->destinationPrint); if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) { $_user = substr($caller_els[0], 0, strlen($caller_els[0])-3).'xxx'; } else { $_user = 'destination'; } if (count($caller_els) == 2) { $this->destinationPrint = $_user.'@'.$caller_els[1]; } else { $this->destinationPrint = $_user; } $caller_els = explode("@", $this->cNumberPrint); if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) { $_user = substr($caller_els[0], 0, strlen($caller_els[0])-3).'xxx'; } else { $_user = 'dialedNumber'; } if (count($caller_els) == 2) { $this->cNumberPrint = $_user.'@'.$caller_els[1]; } else { $this->cNumberPrint = $_user; } $caller_els = explode("@", $this->RemoteAddressPrint); if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) { $_user = substr($caller_els[0], 0, strlen($caller_els[0])-3).'xxx'; } else { $_user = 'remoteAddress'; } if (count($caller_els) == 2) { $this->RemoteAddressPrint = $_user.'@'.$caller_els[1]; } else { $this->RemoteAddressPrint = $_user; } // Canonical URI $caller_els = explode("@", $this->CanonicalURIPrint); if (is_numeric($caller_els[0]) && strlen($caller_els[0]>3)) { $_user = substr($caller_els[0], 0, strlen($caller_els[0])-3).'xxx'; } else { $_user = 'canonicalURI'; } if (count($caller_els) == 2) { $this->CanonicalURIPrint = $_user.'@'.$caller_els[1]; } else { $this->CanonicalURIPrint = $_user; } if (is_numeric($this->SipRPIDPrint) && strlen($this->SipRPIDPrint) > 3) { $this->SipRPIDPrint = substr($this->SipRPID, 0, strlen($this->SipRPID)-3).'xxx'; } else { $_user = 'callerId'; } // IP address $this->SourceIP = 'xxx.xxx.xxx.xxx'; } } } -class CDRS_opensips_mongo extends CDRS_opensips -{ - public $CDR_class = "CDR_opensips_mongo"; - public $mongo_db_ro = null; - public $mongo_db_rw = null; - - function getCDRtables() - { - if (!is_object($this->mongo_db_rw) && !$this->initDatabaseConnection) { - return array(); - } - - $_tables=array(); - try { - $_tables=$this->mongo_db_rw->listCollections(); - } catch (Exception $e) { - printf("

Caught Mongo exception in getCDRtables(): %s", $e->getMessage()); - } - - $t=count($_tables); - if ($this->table) { - $this->tables[]=$this->table; - } - - foreach ($_tables as $_table) { - $_table=strval($_table); - if (preg_match("/^.*\.(radacct\d{6})$/", $_table, $m)) { - if ($list_t > 24) { - break; - } - if (!in_array($m[1], $this->tables)) { - $this->tables[]=$m[1]; - } - $list_t++; - } - $t--; - } - - $this->tables=array_unique($this->tables); - } - - function initDatabaseConnection() - { - if ($this->DATASOURCES[$this->cdr_source]['mongo_db']) { - $mongo_db = $this->CDRTool['mongo_db'][$this->DATASOURCES[$this->cdr_source]['mongo_db']]; - $mongo_uri = $mongo_db['uri']; - $mongo_replicaSet = $mongo_db['replicaSet']; - $mongo_database = $mongo_db['database']; - try { - $mongo_connection_ro = new Mongo("mongodb://$mongo_uri?readPreference=secondaryPreferred", array("replicaSet" => $mongo_replicaSet)); - $this->mongo_db_ro = $mongo_connection_ro->selectDB($mongo_database); - $mongo_connection_rw = new Mongo("mongodb://$mongo_uri?readPreference=primaryPreferred", array("replicaSet" => $mongo_replicaSet)); - $this->mongo_db_rw = $mongo_connection_rw->selectDB($mongo_database); - return true; - } catch (Exception $e) { - printf("

Caught exception in initDatabaseConnection(): %s", $e->getMessage()); - return false; - } - } - return true; - } - - function getMongoTable($table, $rw=false) - { - try { - if ($rw) { - if (!$this->mongo_db_rw && !$this->initDatabaseConnection()) { - return null; - } - $table = $this->mongo_db_rw->selectCollection($table); - } else { - if (!$this->mongo_db_ro && !$this->initDatabaseConnection()) { - return null; - } - $table = $this->mongo_db_ro->selectCollection($table); - } - return $table; - } catch (Exception $e) { - printf("

Caught exception in getMongoTable(): %s", $e->getMessage()); - } - return null; - } - - function initCDRFields() - { - // init names of CDR fields - foreach (array_keys($this->CDRFields) as $field) { - $mongo_field = $field; - $_field = $field."Field"; - $this->$_field = $mongo_field; - } - } - - function _readCDRFieldsFromDB($mongo_result) - { - foreach (array_keys($this->CDRFields) as $field) { - $CDRStructure[$this->CDRFields[$field]] = $mongo_result[$field]; - } - return $CDRStructure; - } - - function getUnNormalized($where="", $table) - { - // TODO - return 0; - } - - function show() - { - global $perm; - - foreach ($this->FormElements as $_el) { - ${$_el} = trim($_REQUEST[$_el]); - } - - if ($begin_time) { - list($begin_hour, $begin_min) = explode(":", $begin_time); - } - - if ($end_time) { - list($end_hour, $end_min) = explode(":", $end_time); - } - - if ($begin_date) { - list($begin_year, $begin_month, $begin_day) = explode("-", $begin_date); - } - - if ($end_date) { - list($end_year, $end_month, $end_day) = explode("-", $end_date); - } - - // overwrite some elements based on user rights - if ($this->CDRTool['filter']['gateway']) { - $gateway = $this->CDRTool['filter']['gateway']; - } - - if (!$this->export) { - if (!$begin_datetime) { - $begin_datetime = "$begin_year-$begin_month-$begin_day $begin_hour:$begin_min"; - $begin_datetime_timestamp = mktime($begin_hour, $begin_min, 0, $begin_month, $begin_day, $begin_year); - } else { - $begin_datetime_timestamp = $begin_datetime; - $begin_datetime = Date("Y-m-d H:i", $begin_datetime); - } - - if (!$end_datetime) { - $end_datetime_timestamp = mktime($end_hour, $end_min, 0, $end_month, $end_day, $end_year); - $end_datetime = "$end_year-$end_month-$end_day $end_hour:$end_min"; - } else { - $end_datetime_timestamp = $end_datetime; - $end_datetime = Date("Y-m-d H:i", $end_datetime); - } - } else { - $begin_datetime = Date("Y-m-d H:i", $begin_datetime); - $end_datetime = Date("Y-m-d H:i", $end_datetime); - } - - if (!$order_by || (!$group_by && $order_by == "group_by")) { - $order_by = $this->idField; - } - - $mongo_where = array(); - - if (!$cdr_table) { - $cdr_table=$this->table; - } - $mongo_table_ro = $this->getMongoTable($cdr_table); - $mongo_table_rw = $this->getMongoTable($cdr_table, true); - - $this->url = sprintf("?cdr_source=%s&cdr_table=%s", $this->cdr_source, $cdr_table); - - if ($this->CDRTool['filter']['domain']) { - $this->url .= sprintf("&Realms=%s", urlencode($this->CDRTool['filter']['domain'])); - $Realms = explode(" ", $this->CDRTool['filter']['domain']); - } elseif ($Realms) { - $this->url .= sprintf("&Realms=%s", urlencode($Realms)); - $Realms = explode(" ", $Realms); - } - - if ($this->CDRTool['filter']['aNumber']) { - $this->url .= sprintf("&UserName=%s", urlencode($this->CDRTool['filter']['aNumber'])); - } - - if ($this->CDRTool['filter']['after_date']) { - $mongo_where[$this->startTimeField] = array('$gte' => $this->CDRTool['filter']['after_date']); - } - - if ($order_by) { - $this->url.=sprintf("&order_by=%s&order_type=%s", addslashes($order_by), addslashes($order_type)); - } - - $this->url.=sprintf("&begin_datetime=%s", urlencode($begin_datetime_timestamp)); - $this->url.=sprintf("&end_datetime=%s", urlencode($end_datetime_timestamp)); - - if (!$call_id && $begin_datetime && $end_datetime) { - $mongo_where[$this->startTimeField] = array('$gte' => $begin_datetime, '$lt' => $end_datetime); - } else { - $mongo_where[$this->startTimeField] = array('$gte' => '1970-01-01'); - } - - if ($MONTHYEAR) { - $mongo_where[$this->startTimeField] = new MongoRegex("/^$MONTHYEAR/"); - $this->url.= sprintf("&MONTHYEAR=%s", urlencode($MONTHYEAR)); - } - - if ($flow) { - $this->url.=sprintf("&flow=%s", urlencode($flow)); - $mongo_where[$this->flowField] = $flow; - } - - if ($this->CDRTool['filter']['aNumber']) { - // force user to see only CDRS with his a_numbers - $mongo_where['$or'] = array(array($this->usernameField => $this->CDRTool['filter']['aNumber']), array($this->CanonicalURIField => $this->CDRTool['filter']['aNumber'])); - $UserName_comp = 'equal'; - $UserName = $this->CDRTool['filter']['aNumber']; - } - - if ($UserName_comp == "empty") { - $mongo_where[$this->usernameField] = ''; - $this->url .= sprintf("&UserName_comp=%s", urlencode($UserName_comp)); - } elseif (strlen($UserName) && !$this->CDRTool['filter']['aNumber']) { - if (!$UserName_comp) { - $UserName_comp='begin'; - } - - if ($UserName_comp=="begin") { - $mongo_where[$this->usernameField] = new MongoRegex("/^$UserName/"); - } elseif ($UserName_comp=="contain") { - $mongo_where[$this->usernameField] = new MongoRegex("/$UserName/"); - } elseif ($UserName_comp=="equal") { - $mongo_where[$this->usernameField] = $UserName; - } else { - $mongo_where[$this->usernameField] = ''; - } - - $this->url.=sprintf("&UserName=%s&UserName_comp=%s", urlencode($UserName), $UserName_comp); - } - - $a_number=trim($a_number); - if ($a_number_comp == "empty") { - $mongo_where[$this->aNumberField] = ''; - $this->url.=sprintf("&a_number_comp=%s", urlencode($a_number_comp)); - } elseif (strlen($a_number)) { - $a_number=urldecode($a_number); - if (!$a_number_comp) { - $a_number_comp="equal"; - } - - $this->url.=sprintf("&a_number=%s", urlencode($a_number)); - - if ($a_number_comp=="begin") { - $mongo_where[$this->aNumberField] = new MongoRegex("/^$a_number/"); - } elseif ($a_number_comp=="contain") { - $mongo_where[$this->aNumberField] = new MongoRegex("/$a_number/"); - } elseif ($a_number_comp=="equal") { - $mongo_where[$this->aNumberField] = $a_number; - } - - $this->url.=sprintf("&a_number_comp=%s", urlencode($a_number_comp)); - } - - $c_number=trim($c_number); - if ($c_number_comp == "empty") { - $mongo_where[$this->CanonicalURIField] = ''; - $this->url.=sprintf("&c_number_comp=%s", urlencode($c_number_comp)); - } elseif (strlen($c_number)) { - $c_number=urldecode($c_number); - if (!$c_number_comp) { - $c_number_comp="begin"; - } - - if (!$c_number_comp || $c_number_comp=="begin") { - $mongo_where[$this->CanonicalURIField] = new MongoRegex("/^$c_number/"); - } elseif ($c_number_comp=="contain") { - $mongo_where[$this->CanonicalURIField] = new MongoRegex("/$c_number/"); - } elseif ($c_number_comp=="equal") { - $mongo_where[$this->CanonicalURIField] = $c_number; - } - $this->url.=sprintf("&c_number=%s&c_number_comp=%s", urlencode($c_number), urlencode($c_number_comp)); - } - - $Realm=trim($Realm); - - if ($Realms) { - $d_array=array(); - foreach ($Realms as $realm) { - $d_array[] = array($this->domainField => $realm); - } - $mongo_where['$or'] = $d_array; - } elseif ($Realm) { - $Realm=urldecode($Realm); - $mongo_where[$this->domainField] = $Realm; - $this->url.=sprintf("&Realm=%s", urlencode($Realm)); - } - - $BillingId=trim($BillingId); - if (preg_match("/^\d+$/", $BillingId) && $this->BillingIdField) { - $mongo_where[$this->BillingIdField] = $BillingId; - $this->url.=sprintf("&BillingId=%s", urlencode($BillingId)); - } - - if ($application) { - $mongo_where[$this->applicationField] = new MongoRegex("/$application/"); - $this->url.=sprintf("&application=%s", urlencode($application)); - } - - if ($DestinationId) { - if ($DestinationId=="empty") { - $DestinationIdSQL=""; - } else { - $DestinationIdSQL=$DestinationId; - } - $mongo_where[$this->DestinationIdField] = $DestinationIdSQL; - $this->url.=sprintf("&DestinationId=%s", urlencode($DestinationId)); - } - - if (strlen(trim($ExcludeDestinations))) { - # TODO: migrateb clause to mongo - $ExcludeDestArray = explode(" ", trim($ExcludeDestinations)); - - foreach ($ExcludeDestArray as $exclDst) { - if (preg_match("/^0+(\d+)$/", $exclDst, $m)) { - $exclDest_id=$m[1]; - } else { - $exclDest_id=$exclDst; - } - - $where .= " and ". - $this->CanonicalURIField. - " not like '". - addslashes(trim($exclDst)). - "'"; - } - - $this->url.=sprintf("&ExcludeDestinations=%s", urlencode($ExcludeDestinations)); - } - - $call_id=trim($call_id); - - if ($call_id) { - $call_id=urldecode($call_id); - $mongo_where[$this->callIdField] = $call_id; - $this->url.=sprintf("&call_id=%s", urlencode($call_id)); - } - - if ($sip_proxy) { - $sip_proxy=urldecode($sip_proxy); - $mongo_where[$this->SipProxyServerField] = $sip_proxy; - $this->url.=sprintf("&sip_proxy=%s", urlencode($sip_proxy)); - } - - if ($media_relay) { - $media_relay=urldecode($media_relay); - $mongo_where[$this->MediaRelayField] = $media_relay; - $this->url.=sprintf("&media_relay=%s", urlencode($media_relay)); - } - - if ($SipCodec) { - $this->url.=sprintf("&SipCodec=%s", urlencode($SipCodec)); - if ($SipCodec != "empty") { - $mongo_where[$this->SipCodecField] = $SipCodec; - } else { - $mongo_where[$this->SipCodecField] = ''; - } - } - - if ($SipRPID) { - $this->url.=sprintf("&SipRPID=%s", urlencode($SipRPID)); - if ($SipRPID != "empty") { - $mongo_where[$this->SipRPIDField] = $SipRPID; - } else { - $mongo_where[$this->SipRPIDField] = ''; - } - } - - if ($UserAgent) { - $mongo_where[$this->UserAgentField] = $UserAgent; - $this->url.=sprintf("&UserAgent=%s", urlencode($UserAgent)); - } - - if (strlen($sip_status)) { - $mongo_where[$this->disconnectField] = $sip_status; - $this->url.=sprintf("&sip_status=%s", urlencode($sip_status)); - } - - if ($sip_status_class) { - $mongo_where[$this->disconnectField] = new MongoRegex("/^$sip_status_class/"); - $this->url.=sprintf("&sip_status_class=%s", urlencode($sip_status_class)); - } - - if ($this->CDRTool[filter]["gateway"]) { - $mongo_where[$this->gatewayField] = $this->CDRTool[filter]["gateway"]; - } elseif ($gateway) { - $gateway=urldecode($gateway); - $mongo_where[$this->gatewayField] = $gateway; - $this->url.=sprintf("&gateway=%s", $gateway); - } - - if ($duration) { - if (preg_match("/\d+/", $duration)) { - $mongo_where[$this->durationField] = array('$gt' => 0); - } elseif (preg_match("/onehour/", $duration)) { - $mongo_where[$this->durationField] = array('$lt' => 3610, '$gt' => 3530); - } elseif ($duration == "zero") { - $mongo_where[$this->durationField] = 0; - } elseif ($duration == "zeroprice" && $this->priceField) { - $mongo_where[$this->durationField] = array('$gt' => 0); - $mongo_where[$this->priceField] = null; - } elseif ($duration == "nonzero") { - $mongo_where[$this->durationField] = array('$gt' => 0); - } elseif ($duration == "onewaymedia") { - $mongo_where['$or'] = array(array($this->outputTrafficField => 0), array($this->inputTrafficField => 0)); - } elseif ($duration == "nomedia") { - $mongo_where[$this->inputTrafficField] = 0; - $mongo_where[$this->outputTrafficField] = 0; - } - $this->url.=sprintf("&duration=%s", urlencode($duration)); - } - - if ($media_info) { - $this->url.=sprintf("&media_info=%s", urlencode($media_info)); - $mongo_where[$this->MediaInfoField] = $media_info; - } - - $this->url.=sprintf("&maxrowsperpage=%s", addslashes($this->maxrowsperpage)); - $url_calls = $this->scriptFile.$this->url."&action=search"; - - if ($group_by) { - $this->url.=sprintf("&group_by=%s", urlencode($group_by)); - } - - $this->url_edit = $this->scriptFile.$this->url."&action=edit"; - $this->url_run = $this->scriptFile.$this->url."&action=search"; - $this->url_export = $_SERVER["PHP_SELF"].$this->url."&action=search&export=1"; - - if ($duration == "unnormalized") { - $mongo_where[$this->normalizedField] = '0'; - } - - if ($duration == "unnormalized_duration") { - $mongo_where[$this->normalizedField] = '0'; - $mongo_where[$this->durationField] = array('$gt' => 0); - } - - if ($group_by) { - $this->group_byOrig=$group_by; - - if ($group_by == "hour") { - $group_by = "HOUR(AcctStartTime)"; - } elseif (preg_match("/^DAY/", $group_by)) { - $group_by = "$group_by(AcctStartTime)"; - } elseif (preg_match("/BYMONTH/", $group_by)) { - $group_by = "DATE_FORMAT(AcctStartTime,'%Y-%m')"; - } elseif (preg_match("/BYYEAR/", $group_by)) { - $group_by = "DATE_FORMAT(AcctStartTime,'%Y')"; - } elseif ($group_by=="UserAgentType") { - $group_by = "SUBSTRING_INDEX($this->SipUserAgentsField, ' ', '1')"; - } - - $this->group_by=$group_by; - - if ($group_by==$this->callIdField) { - $having=sprintf(" having count(%s) > 1 ", addslashes($group_by)); - } - - $field = array_search($group_by, $this->CDRFields); - $pipeline=array( - array('$match' => $mongo_where), - array('$group' => array("_id" => sprintf('$%s', $field), - 'calls' => array('$sum' => 1))), - array('$match' => array('calls' => array('$gte' => 0))) - ); - - $rows = 0; - if ($mongo_table_ro) { - try { - $group_results = $mongo_table_ro->aggregate($pipeline); - $rows = count($group_results); - } catch (Exception $e) { - printf("

Caught Mongo exception in show(): %s", $e->getMessage()); - } - } - } else { - $rows = 0; - if ($mongo_table_ro) { - try { - $rows = $mongo_table_ro->find($mongo_where)->slaveOkay()->count(); - } catch (Exception $e) { - printf("

Caught Mongo exception in show(): %s", $e->getMessage()); - } - } - } - - dprint_r($mongo_where); - - $this->rows=$rows; - - if ($this->CDRTool['filter']['aNumber']) { - $this->showResultsMenuSubscriber('0', $begin_datetime, $end_datetime); - } else { - $this->showResultsMenu('0', $begin_datetime, $end_datetime); - } - - if (!$this->next) { - $i=0; - $this->next=0; - } else { - $i=$this->next; - } - $j=0; - $z=0; - - - if ($rows>0) { - if ($call_id && $ReNormalize) { - if ($mongo_table_rw) { - $mongo_table_rw->update(array($this->normalizedField=>0), array('$set' => array($this->callIdField => $call_id))); - } - } - - if ($UnNormalizedCalls=$this->getUnNormalized($mongo_where, $cdr_table)) { - if (!$this->DATASOURCES[$this->cdr_source]['skipNormalizeOnPageLoad']) { - if ($UnNormalizedCalls < $this->maxCDRsNormalizeWeb) { - $this->NormalizeCDRS($mongo_where, $cdr_table); - if (!$this->export && $this->status['normalized']) { - print "

"; - printf("%d CDRs normalized. ", $this->status['normalized']); - if ($this->status['cached_keys']['saved_keys']) { - printf("Quota usage updated for %d accounts. ", $this->status['cached_keys']['saved_keys']); - } - print "
"; - } - } - } - } - - if ($rows > $this->maxrowsperpage) { - $maxrows=$this->maxrowsperpage+$this->next; - if ($maxrows > $rows) { - $maxrows=$rows; - $prev_rows=$maxrows; - } - } else { - $maxrows=$rows; - } - - if ($duration == "unnormalized") { - // if display un normalized calls we must substract - // the amount of calls normalized above - $maxrows=$maxrows-$this->status['normalized']; - } - - $mongo_order_by = '_id'; - - if ($order_type == DESC) { - $mongo_order_type = -1; - } else { - $mongo_order_type = 1; - } - - if ($group_by) { - if ($order_by == "group_by") { - $mongo_order_by = '_id'; - } else { - $_tmp = array_search($order_by, $this->CDRFields); - if (in_array($_tmp, array('price', 'duration','inputTraffic', 'outputTraffic'))) { - $mongo_order_by = $_tmp; - } else { - $mongo_order_by = 'calls'; - } - } - - $pipeline = array( - array('$match' => $mongo_where), - array('$group' => array( - '_id' => sprintf('$%s', $field), - 'calls' => array( '$sum' => 1), - 'duration' => array( '$sum' => '$duration'), - 'inputTraffic' => array( '$sum' => '$inputTraffic'), - 'outputTraffic' => array( '$sum' => '$outputTraffic'), - 'price' => array( '$sum' => '$price'), - 'zero' => array( '$sum' => array('$cond'=> array(array('$eq' => array('$duration', 0)), 1, 0 ))), - 'nonzero' => array( '$sum' => array('$cond'=> array(array('$gt' => array('$duration', 0)), 1, 0 ))) - )), - array('$match' => array('calls' => array('$gte' => 0))), - array('$sort' => array($mongo_order_by => $mongo_order_type)), - array('$skip' => intval($i)), - array('$limit' => intval($this->maxrowsperpage)) - ); - - //dprint_r($pipeline); - - try { - $group_results = $mongo_table_ro->aggregate($pipeline); - } catch (Exception $e) { - printf("

Caught Mongo exception in show(): %s", $e->getMessage()); - } - - $this->showTableHeaderStatistics(); - - foreach ($group_results as $result) { - $found=$i+1; - - $mygroup = $result['_id']; - - $calls = $result['calls']; - $seconds = $result['duration']; - $price = $result['price']; - $zero = $result['zero']; - $zeroP = $calls/$zero * 100; - $nonzero = $result['nonzero']; - $nonzeroP = $calls/$nonzero * 100; - $seconds_print = number_format($seconds, 0); - $minutes = number_format($seconds/60, 0, "", ""); - $minutes_print = number_format($seconds/60, 0); - $hours = sec2hms($seconds); - - $AcctInputOctets = number_format($result['inputTraffic'] * 2/ 1024/1024, 2, ".", ""); - $AcctOutputOctets = number_format($result['outputTraffic'] * 2/ 1024/1024, 2, ".", ""); - $NetRateIn = $result['inputTraffic']*8*2/1024/$seconds; - $NetRateOut = $result['outputTraffic']*8*2/1024/$seconds; - $success = number_format($nonzero/$calls*100, 2, ".", ""); - $failure = number_format($zero/$calls*100, 2, ".", ""); - - $NetworkRateIn = number_format($NetRateIn, 2); - $NetworkRateOut = number_format($NetRateOut, 2); - $NetworkRate = max($NetworkRateIn, $NetworkRateOut); - - $rr = floor($found/2); - $mod = $found - $rr * 2; - - if ($mod == 0) { - $inout_color = "lightgrey"; - } else { - $inout_color = "white"; - } - - $traceValue=""; - $mygroup_print=quoted_printable_decode($mygroup); - - if ($this->group_byOrig == $this->DestinationIdField) { - if ($this->CDRTool['filter']['domain'] && $this->destinations[$this->CDRTool['filter']['domain']]) { - list($_dst_id, $_dst_name) = $this->getPSTNDestinationId($mygroup, '', $this->CDRTool['filter']['domain']); - $description=$_dst_name; - } else { - $description=$this->destinations[0]["default"][$mygroup]["name"]; - } - - if ($mygroup) { - $traceValue=$mygroup; - } else { - $traceValue="empty"; - } - } elseif ($this->group_byOrig == $this->aNumberField) { - // Normalize Called Station Id - $N=$this->NormalizeNumber($mygroup); - $mygroup_print=$N['username']."@".$N[domain]; - $description=""; - $traceField = "a_number"; - $traceValue = urlencode($mygroup); - } elseif ($this->group_byOrig == $this->CanonicalURIField) { - $traceField = "c_number"; - $traceValue = urlencode($mygroup); - } elseif ($this->group_byOrig == $this->SipProxyServerField) { - $traceField="sip_proxy"; - $traceValue=urlencode($mygroup); - } elseif ($this->group_byOrig == $this->MediaRelayField) { - $traceField="media_relay"; - $traceValue=urlencode($mygroup); - } elseif ($this->group_byOrig == $this->SipCodecField) { - $traceField="SipCodec"; - } elseif (preg_match("/UserAgent/", $this->group_byOrig)) { - $traceField="UserAgent"; - } elseif (preg_match("/^BY/", $this->group_byOrig)) { - $traceField="MONTHYEAR"; - } elseif ($this->group_byOrig == $this->callIdField) { - $traceField="call_id"; - } elseif ($this->group_byOrig == "SourceIP") { - $traceField = "gateway"; - } elseif ($this->group_byOrig == "SipResponseCode") { - $description = $this->disconnectCodesDescription[$mygroup]; - $traceField="sip_status"; - } elseif ($this->group_byOrig == "SipApplicationType") { - $traceField="application"; - } elseif ($this->group_byOrig == "ServiceType") { - $traceField="flow"; - } else { - $description=""; - } - - if (!$traceField) { - $traceField = $group_by; - } - - if (!$traceValue) { - $traceValue = $mygroup; - } - - if (!$traceValue) { - $traceValue=""; - $comp_type="empty"; - } else { - $comp_type="begin"; - } - - $traceValue_enc=urlencode($traceValue); - - if (!$this->export) { - print " - - $found - $calls - $seconds_print - $minutes_print - $hours - "; - if ($perm->have_perm("showPrice")) { - $pricePrint=number_format($price, 4, ".", ""); - } else { - $pricePrint='x.xxx'; - } - print " - $pricePrint - $AcctInputOctets - $AcctOutputOctets - $success% - ($nonzero calls) - $failure% - ($zero calls) - $mygroup_print - $description - "; - printf("Display calls", $url_calls, $traceField, $traceValue_enc, $traceField, $comp_type); - print " - - "; - } else { - print "$found,"; - print "$calls,"; - print "$seconds,"; - print "$minutes,"; - print "$hours,"; - if ($perm->have_perm("showPrice")) { - $pricePrint = $price; - } else { - $pricePrint = 'x.xxx'; - } - print "$pricePrint,"; - print "$AcctInputOctets,"; - print "$AcctOutputOctets,"; - print "$success,"; - print "$nonzero,"; - print "$failure,"; - print "$zero,"; - print "$mygroup_print,"; - print "$description"; - print "\n"; - } - $i++; - } - - if (!$this->export) { - print " - - "; - } - } else { - if (!$this->export) { - // printf ("

For more information about each call click on its Id column.
"); - } - - if ($order_by=="zeroP" || $order_by=="nonzeroP") { - $order_by="timestamp"; - } - - if ($mongo_table_ro) { - $cursor = $mongo_table_ro->find($mongo_where)->sort(array($mongo_order_by=>$mongo_order_type))->skip($i)->limit($this->maxrowsperpage)->slaveOkay(); - } else { - $cursor = array(); - } - - if ($this->CDRTool['filter']['aNumber']) { - $this->showTableHeaderSubscriber(); - } else { - if (!$this->export) { - $this->showTableHeader(); - } else { - $this->showExportHeader(); - } - } - - foreach ($cursor as $result) { - global $found; - $found=$i+1; - - $Structure=$this->_readCDRFieldsFromDB($result); - $CDR = new $this->CDR_class($this, $Structure); - - if ($this->CDRTool['filter']['aNumber']) { - $CDR->showSubscriber(); - } else { - if (!$this->export) { - $CDR->show(); - } else { - $CDR->export(); - } - } - - $i++; - } - - if (!$this->export) { - print ""; - } - } - $this->showPagination($this->next, $maxrows); - } - } -} - -class CDR_opensips_mongo extends CDR_opensips { -} - class SIP_trace { public $enableThor = false; public $trace_array = array(); public $traced_ip = array(); public $SIPProxies = array(); public $mediaTrace = false; public $thor_nodes = array(); public $hostnames = array(); public function SIP_trace($cdr_source) { global $DATASOURCES, $auth; $this->cdr_source = $cdr_source; $this->cdrtool = new DB_CDRTool(); if (!is_array($DATASOURCES[$this->cdr_source])) { $log = sprintf("Error: datasource '%s' is not defined", $this->cdr_source); print $log; return 0; } if (strlen($DATASOURCES[$this->cdr_source]['enableThor'])) { $this->enableThor = $DATASOURCES[$this->cdr_source]['enableThor']; } if (strlen($DATASOURCES[$this->cdr_source]['mediaTrace'])) { $this->mediaTrace = $DATASOURCES[$this->cdr_source]['mediaTrace']; } if ($this->enableThor) { require("/etc/cdrtool/ngnpro_engines.inc"); require_once("ngnpro_soap_library.php"); if ($DATASOURCES[$this->cdr_source]['soapEngineId'] && in_array($DATASOURCES[$this->cdr_source]['soapEngineId'], array_keys($soapEngines))) { $this->soapEngineId=$DATASOURCES[$this->cdr_source]['soapEngineId']; $this->SOAPlogin = array( "username" => $soapEngines[$this->soapEngineId]['username'], "password" => $soapEngines[$this->soapEngineId]['password'], "admin" => true ); $this->SOAPurl=$soapEngines[$this->soapEngineId]['url']; $this->SoapAuth = array('auth', $this->SOAPlogin , 'urn:AGProjects:NGNPro', 0, ''); // Instantiate the SOAP client $this->soapclient = new WebService_NGNPro_SipPort($this->SOAPurl); $this->soapclient->setOpt('curl', CURLOPT_TIMEOUT, 5); $this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0); $this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0); if (is_array($soapEngines[$this->soapEngineId]['hostnames'])) { $this->hostnames=$soapEngines[$this->soapEngineId]['hostnames']; } } else { printf("

Error: soapEngineID not defined in datasource %s", $this->cdr_source); return false; } } else { $this->table = $DATASOURCES[$this->cdr_source]['table']; $db_class = $DATASOURCES[$this->cdr_source]['db_class']; $this->purgeRecordsAfter = $DATASOURCES[$this->cdr_source]['purgeRecordsAfter']; if (class_exists($db_class)) { $this->db = new $db_class; } else { printf("

Error: database class '%s' is not defined", $db_class); return false; } } if (is_object($auth)) { $this->isAuthorized=1; } if (is_array($DATASOURCES[$this->cdr_source]['SIPProxies'])) { $this->SIPProxies = $DATASOURCES[$this->cdr_source]['SIPProxies']; } } private function isProxy($ip, $sip_proxy = '') { if (!$ip) { return false; } if (!$this->enableThor) { if (!is_array($this->SIPProxies)) { return false; } if (in_array($ip, array_keys($this->SIPProxies))) { return true; } } elseif ($sip_proxy) { if (isset($this->thor_nodes[$ip])) { return true; } else { if (isThorNode($ip, $sip_proxy)) { $this->thor_nodes[$ip]=1; return true; } else { return false; } } } return false; } private function getTrace($proxyIP, $callid, $fromtag, $totag) { if ($this->enableThor) { // get trace using soap request if (!$proxyIP || !$callid || !$fromtag) { return false; } if (!is_object($this->soapclient)) { print "Error: soap client is not defined."; return false; } $filter = array( 'nodeIp' => $proxyIP, 'callId' => $callid, 'fromTag' => $fromtag, 'toTag' => $totag ); $this->soapclient->addHeader($this->SoapAuth); $result = $this->soapclient->getSipTrace($filter); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault = $result->getFault(); $error_code = $result->getCode(); printf( "

Error from %s


%s (%s)
", $this->SOAPurl, $error_fault->detail->exception->errorstring, $error_fault->detail->exception->errorcode ); return false; } $columns = 0; $traces = json_decode($result); $trace_array = array(); foreach ($traces as $_trace) { if (preg_match("/^(udp|tcp|tls):(.*):(.*)$/", $_trace->to_ip, $m)) { $toip = $m[2]; $transport = $m[1]; $toport = $m[3]; } elseif (preg_match("/^(.*):(.*)$/", $_trace->to_ip, $m)) { $toip = $m[1]; $transport = 'udp'; $toport = $m[2]; } else { $toip = $_trace->to_ip; $transport = $_trace->to_proto; $toport = $_trace->to_port; } if (preg_match("/^(udp|tcp|tls):(.*):(.*)$/", $_trace->from_ip, $m)) { $fromip = $m[2]; $fromport = $m[3]; } elseif (preg_match("/^(.*):(.*)$/", $_trace->from_ip, $m)) { $fromip = $m[1]; $fromport = $m[2]; } else { $fromip = $_trace->from_ip; $fromport = $_trace->from_port; } if (!isset($this->column[$fromip])) { $this->column[$fromip] = $columns + 1; $this->column_port[$fromip] = $fromport; $columns++; } if (!isset($this->column[$toip])) { $this->column[$toip] = $columns+1; $this->column_port[$toip] = $toport; $columns++; } preg_match("/^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$/", $_trace->time_stamp, $m); $timestamp = mktime($m[4], $m[5], $m[6], $m[2], $m[3], $m[1]); $idx=$proxyIP.'_'.$_trace->id; $trace_array[$idx] = array ( 'id' => $idx, 'direction' => $_trace->direction, 'fromip' => $fromip, 'toip' => $toip, 'fromport' => $fromport, 'toport' => $toport, 'method' => $_trace->method, 'transport' => $transport, 'date' => $_trace->time_stamp, 'status' => $_trace->status, 'timestamp' => $timestamp, 'msg' => $_trace->message, 'md5' => md5($_trace->message) ); } $this->trace_array=$trace_array; $this->rows = count($this->trace_array); } else { // get trace from SQL if (!is_object($this->db)) { print "

Error: no database connection defined"; return false; } $query = sprintf( " select *, UNIX_TIMESTAMP(time_stamp) as timestamp from %s where callid = '%s' order by id asc ", addslashes($this->table), addslashes($callid) ); if (!$this->db->query($query)) { printf("Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno); return false; } $this->rows = $this->db->num_rows(); $columns = 0; while ($this->db->next_record()) { if (preg_match("/^(udp|tcp|tls):(.*):(.*)$/", $this->db->f('toip'), $m)) { $toip = $m[2]; $transport = $m[1]; $toport = $m[3]; } elseif (preg_match("/^(.*):(.*)$/", $this->db->f('toip'), $m)) { $toip = $m[1]; $transport = 'udp'; $toport = $m[2]; } else { $toip = $this->db->f('toip'); $toport = '5060'; } if (preg_match("/^(udp|tcp|tls):(.*):(.*)$/", $this->db->f('fromip'), $m)) { $fromip = $m[2]; $fromport = $m[3]; } elseif (preg_match("/^(.*):(.*)$/", $this->db->f('fromip'), $m)) { $fromip = $m[1]; $fromport = $m[2]; } else { $fromip = $this->db->f('fromip'); $transport = 'udp'; $fromport = '5060'; } if (!$this->column[$fromip]) { $this->column[$fromip]=$columns+1; $this->column_port[$fromip]=$fromport; $columns++; } if (!$this->column[$toip]) { $this->column[$toip] = $columns + 1; $this->column_port[$toip]=$toport; $columns++; } $this->trace_array[$this->db->f('id')] = array ( 'id' => $this->db->f('id'), 'direction' => $this->db->f('direction'), 'fromip' => $fromip, 'toip' => $toip, 'method' => $this->db->f('method'), 'fromport' => $fromport, 'toport' => $toport, 'transport' => $transport, 'date' => $this->db->f('time_stamp'), 'status' => $this->db->f('status'), 'timestamp' => $this->db->f('timestamp'), 'msg' => $this->db->f('msg'), 'md5' => md5($this->db->f('msg')) ); } } } private function printLabelProtocolPort($transport, $port) { echo ''; if ($transport == 'tls') { echo " "; } printf('%s: %d', strtoupper($transport), $port); echo ''; } public function show($proxyIP, $callid, $fromtag, $totag) { $action = $_REQUEST['action']; $toggleVisibility = $_REQUEST['toggleVisibility']; if ($action == 'toggleVisibility') { $this->togglePublicVisibility($callid, $fromtag, $toggleVisibility); } if ($_SERVER['HTTPS'] == "on") { $protocolURL = "https://"; } else { $protocolURL = "http://"; } $this->getTrace($proxyIP, $callid, $fromtag, $totag); /* No trace can be found */ if (!count($this->trace_array)) { echo "

SIP trace for session id $callid is not available.

"; return; } echo "

CDRTool SIP trace
Call ID: $callid $authorize

"; $basicURL = $protocolURL.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; $fullURL = $basicURL; print "URLs for this trace: HTML | TEXT"; if ($this->mediaTrace) { $media_query = array( 'cdr_source' => $this->mediaTrace, 'callid' => $callid, 'fromtag' => $fromtag, 'totag' => $totag, 'proxyIP' => $proxyIP ); $this->mediaTraceLink = sprintf( "

Click here for RTP media information

", http_build_query($media_query) ); } print "

Click on each packet to expand its body content

$this->mediaTraceLink
"; foreach (array_keys($this->trace_array) as $key) { $this->trace_array[$key]['isProxy'] = 0; if ($this->trace_array[$key]['direction'] == 'in') { if (is_array($this->SIPProxies)) { $thisIP=explode(":", $this->trace_array[$key]['fromip']); if ($this->isProxy($thisIP[0], $proxyIP)) { $this->trace_array[$key]['isProxy'] = 1; } } if ($this->trace_array[$key]['fromip'] == $this->trace_array[$key]['toip']) { $arrow_direction = "loop"; } elseif ($this->column[$this->trace_array[$key]['fromip']] < $this->column[$this->trace_array[$key]['toip']]) { $arrow_direction = "right"; } else { $arrow_direction = "left"; } $this->trace_array[$key]['msg_possition'] = $this->column[$this->trace_array[$key]['toip']]; $this->trace_array[$key]['arrow_possition'] = $this->column[$this->trace_array[$key]['fromip']]; $this->trace_array[$key]['arrow_direction'] = $arrow_direction; } else { if ($this->trace_array[$key]['fromip'] == $this->trace_array[$key]['toip']) { $arrow_direction = "loop"; } elseif ($this->column[$this->trace_array[$key]['fromip']] < $this->column[$this->trace_array[$key]['toip']]) { $arrow_direction = "right"; } else { $arrow_direction = "left"; } $this->trace_array[$key]['msg_possition'] = $this->column[$this->trace_array[$key]['fromip']]; $this->trace_array[$key]['arrow_possition'] = $this->column[$this->trace_array[$key]['toip']]; $this->trace_array[$key]['arrow_direction'] = $arrow_direction; } } echo " "; $_seen_timeline = array(); foreach (array_keys($this->column) as $_key) { $IPels = explode(":", $_key); if (isset($this->hostnames[$IPels[0]])) { $_hostname = $this->hostnames[$IPels[0]]; } else { $_hostname = $_key; } print ""; } print ""; /* Rows */ $i=0; foreach (array_keys($this->trace_array) as $key) { $i++; $id = $this->trace_array[$key]['id']; $msg = $this->trace_array[$key]['msg']; $fromip = $this->trace_array[$key]['fromip']; $toip = $this->trace_array[$key]['toip']; $date = substr($this->trace_array[$key]['date'], 11); $status = $this->trace_array[$key]['status']; $direction = $this->trace_array[$key]['direction']; $timestamp = $this->trace_array[$key]['timestamp']; $method = $this->trace_array[$key]['method']; $isProxy = $this->trace_array[$key]['isProxy']; $transport = $this->trace_array[$key]['transport']; $msg_possition = $this->trace_array[$key]['msg_possition']; $arrow_possition = $this->trace_array[$key]['arrow_possition']; $arrow_direction = $this->trace_array[$key]['arrow_direction']; $md5 = $this->trace_array[$key]['md5']; if ($i == 1) { $begin_timestamp = $timestamp; } $timeline = $timestamp - $begin_timestamp; $sip_phone_img = getImageForUserAgent($msg); if ($seen_msg[$md5]) { continue; } $SIPclass = substr($status, 0, 1); switch ($SIPclass) { case 6: $status_color = "red"; break; case 5: $status_color = "red"; break; case 4: $status_color = "red"; break; case 3: $status_color = "green"; break; case 2: $status_color = "green"; break; case 1: $status_color = "orange"; break; default: $status_color = "blue"; if ($method == "ACK") { $status_color = 'cyan'; } else if ($method == "CANCEL") { $status_color = 'magenta'; } break; } $_lines = explode("\n", $msg); if (preg_match("/^(.*) SIP/", $_lines[0], $m)) { $_lines[0] = $m[1]; } elseif (preg_match("/^SIP\/2\.0 (.*)/", $_lines[0], $m)) { $_lines[0] = $m[1]; } unset($media); unset($diversions); $media_index=0; $search_ice=0; $search_ip=0; $contact_header=''; foreach ($_lines as $_line) { if (preg_match("/^(Diversion: ).*;(.*)$/", $_line, $m)) { $diversions[]=$m[1].$m[2]; } if (preg_match("/^Cseq:\s*\d+\s*(.*)$/i", $_line, $m)) { $status_for_method=$m[1]; } if (preg_match("/^c=IN \w+ ([\d|\w\.]+)/i", $_line, $m)) { $media['ip']=$m[1]; } if (preg_match("/^m=(\w+) (\d+) /i", $_line, $m)) { $media_index++; $search_ice=1; $search_ip=1; $media['streams'][$media_index] = array( 'type' => $m[1], 'ip' => $media['ip'], 'port' => $m[2], 'ice' => '' ); } if ($search_ip && preg_match("/^c=IN \w+ ([\d|\w\.]+)/i", $_line, $m)) { $media['streams'][$media_index]['ip']=$m[1]; $search_ip=0; } if ($search_ice && preg_match("/^a=ice/i", $_line, $m)) { $media['streams'][$media_index]['ice']="ICE"; $search_ice=0; } } $_els = explode(";", $_lines[0]); $cell_content = "
$_els[0]"; if ($status) { $cell_content .= " for ".$status_for_method.""; } if (is_array($diversions)) { foreach ($diversions as $_diversion) { $cell_content.="
$_diversion"; } } if (is_array($media['streams'])) { foreach (array_keys($media['streams']) as $_key) { $_stream = sprintf( "%s: %s:%s %s", $media['streams'][$_key]['type'], $media['streams'][$_key]['ip'], $media['streams'][$_key]['port'], $media['streams'][$_key]['ice'] ); if ($media['streams'][$_key]['port']) { $cell_content.="
$_stream"; } else { $cell_content.="
$_stream"; } } } $cell_content.="
"; print " "; $packet_length = strlen($msg); print " "; $column_current = 1; while ($column_current <= count($this->column)) { if ($arrow_possition == $column_current) { /* First cell, first port, append extra cell */ if ($column_current < count($this->column) && $column_current < $msg_possition) { print ""; } $arrowColor = $status_color; if ($arrow_direction == 'loop') { print ""; } if ($arrow_possition >= 2 * $msg_possition) { $arrow_span = ($arrow_possition * 2) - 4; echo ""; if ($column_current < count($this->column) && $column_current > $msg_possition) { print ""; } } else { if ($msg_possition == $column_current) { if ($msg_possition < $arrow_possition) { print ""; } echo ""; } if ($arrow_possition == $column_current && $column_current == count($this->column)) { echo ""; } $column_current++; if ($arrow_direction == 'loop') { $seen_msg[$md5]++; } } echo ""; if (is_array($this->SIPProxies)) { $IPels = explode(":", $fromip); $justIP = $IPels[0]; foreach (array_keys($this->SIPProxies) as $localProxy) { if ($localProxy == $justIP) { $direction="out"; break; } } } /* Details */ $trace_span = count($this->column) * 2 + 3; print " "; } print "
Packet Time"; if ($proxyIP != $IPels[0] && $this->isProxy($IPels[0], $proxyIP)) { $trace_query = array( 'cdr_source' => $this->cdr_source, 'callid' => $callid, 'fromtag' => $fromtag, 'totag' => $totag, 'proxyIP' => $IPels[0] ); $trace_link = sprintf( "%s:%s", http_build_query($trace_query), $_hostname, $this->column_port[$_key] ); printf("%s", $trace_link); } else { printf("%s", $_hostname); } print "
$i/$this->rows  $date"; if ($timeline && !isset($_seen_timeline[$timeline])) { printf("  +%ds", $timeline); $_seen_timeline[$timeline] = 1; } print "
$packet_length bytes
"; if ($direction == 'in') { $this->printLabelProtocolPort($transport, $this->trace_array[$key]['fromport']); } else { $this->printLabelProtocolPort($transport, $this->trace_array[$key]['toport']); } echo ""; } else { echo ""; } if ($arrow_direction != 'loop') { print "
"; } if ($arrow_direction == "left") { print "
$cell_content
"; } else { print "
$cell_content
"; } echo "
"; if ($direction == 'in') { $this->printLabelProtocolPort($transport, $this->trace_array[$key]['fromport']); } else { $this->printLabelProtocolPort($transport, $this->trace_array[$key]['toport']); } echo ""; if ($direction == 'out') { $this->printLabelProtocolPort($transport, $this->trace_array[$key]['fromport']); } else { $this->printLabelProtocolPort($transport, $this->trace_array[$key]['toport']); } } else { print ""; if ($direction == 'out') { $this->printLabelProtocolPort($transport, $this->trace_array[$key]['fromport']); } else { $this->printLabelProtocolPort($transport, $this->trace_array[$key]['toport']); } } } elseif ($arrow_possition != $column_current && ( $column_current == 1 || ( $arrow_possition < $column_current && $arrow_possition != $msg_possition) )) { print ""; print ""; print " "; } elseif ($arrow_possition == $msg_possition) { echo ""; if ($direction == 'in') { $this->printLabelProtocolPort($transport, $this->trace_array[$key]['fromport']); } else { $this->printLabelProtocolPort($transport, $this->trace_array[$key]['toport']); } echo "
"; if ($direction == "out") { print "

SIP Proxy

"; } else { if ($sip_phone_img && $sip_phone_img!='unknown.png') { print ""; } else { print ""; } } print "
"; if ($timeline > 0) { printf("

+%s s
(%s)

", $timeline, sec2hms($timeline)); } print "
"; $msg = nl2br(htmlentities($msg)); print "$msg
"; echo "
"; } public function showText($proxyIP, $callid, $fromtag, $totag) { $this->getTrace($proxyIP, $callid, $fromtag, $totag); print "
";
 
         if (!count($this->trace_array)) {
             print "SIP trace for session id $callid is not available.";
             return false;
         }
 
         printf("SIP trace on proxy %s for session %s\n--\n\n", $proxyIP, $callid);
 
         foreach (array_keys($this->trace_array) as $key) {
             $i++;
             printf(
                 "Packet %d at %s from %s to %s (%s)\n",
                 $i,
                 $this->trace_array[$key]['date'],
                 $this->trace_array[$key]['fromip'],
                 $this->trace_array[$key]['toip'],
                 $this->trace_array[$key]['direction']
             );
             printf(
                 "\n%s\n",
                 htmlspecialchars($this->trace_array[$key]['msg'])
             );
             print "---\n";
         }
         print "
"; } public function togglePublicVisibility($callid, $fromtag, $public = '0') { $key="callid-".trim($callid).trim($fromtag); if (!$public) { $query = sprintf("delete from memcache where `key` = '%s'", addslashes($key)); $this->cdrtool->query($query); } else { $query = sprintf("delete from memcache where `key` = '%s'", addslashes($key)); $this->cdrtool->query($query); $query = sprintf("insert into memcache values ('%s','public')", addslashes($key)); $this->cdrtool->query($query); } } public function purgeRecords($days = '') { if ($this->enableThor) { return true; } $b=time(); if ($days) { $this->purgeRecordsAfter = $days; } elseif (!$this->purgeRecordsAfter) { $this->purgeRecordsAfter = 15; } $beforeDate=Date("Y-m-d", time()-$this->purgeRecordsAfter*3600*24); $query = sprintf( "SELECT id as min, time_stamp FROM %s ORDER BY id ASC limit 1", addslashes($this->table) ); if ($this->db->query($query)) { if ($this->db->num_rows()) { $this->db->next_record(); $min=$this->db->f('min'); $begindate=$this->db->f('date'); } else { $log = sprintf("No records found in %s\n", $this->table); print $log; syslog(LOG_NOTICE, $log); return false; } } else { $log = sprintf("Error: %s (%s)\n", $this->db->Error, $query); print $log; syslog(LOG_NOTICE, $log); return false; } $query=sprintf( "select id as max from %s where time_stamp < '%s' order by id DESC limit 1", addslashes($this->table), addslashes($beforeDate) ); if ($this->db->query($query) && $this->db->num_rows()) { $this->db->next_record(); $max=$this->db->f('max'); } else { $log=sprintf( "No records found in %s before %s, records start after %s\n", $this->table, $beforeDate, $begindate ); syslog(LOG_NOTICE, $log); print $log; return false; } $deleted = 0; $i = $min; $interval = 1000; $rows2delete = $max - $min; $found = 0; print "$rows2delete traces to delete between $min and $max\n"; while ($i<=$max) { $found=$found+$interval; if ($i + $interval < $max) { $top=$i; } else { $top=$max; } $query=sprintf( "delete low_priority from %s where id >= '%d' and id <='%d'", addslashes($this->table), addslashes($min), addslashes($top) ); if ($this->db->query($query)) { $deleted = $deleted + $this->db->affected_rows(); } else { $log = sprintf("Error: %s (%s)", $this->db->Error, $this->db->Errno); syslog(LOG_NOTICE, $log); return false; } if ($found > $progress * $rows2delete / 100) { $progress++; if ($progress % 10 == 0) { print "$progress% "; } flush(); } $i = $i + $interval; } print "\n"; $e = time(); $d = $e - $b; $rps = 0; if ($deleted && $d) { $rps=$deleted/$d; } $log = sprintf( "%s records before %s from %s deleted in %d s @ %.0f rps\n", $deleted, $beforeDate, $this->table, $d, $rps ); syslog(LOG_NOTICE, $log); print $log; return true; } } class Media_trace { public $enableThor = false; public $table = 'media_sessions'; function Media_trace($cdr_source) { global $DATASOURCES; $this->cdr_source = $cdr_source; $this->cdrtool = new DB_CDRTool(); if (!is_array($DATASOURCES[$this->cdr_source])) { $log = sprintf("Error: datasource '%s' is not defined", $this->cdr_source); print $log; return 0; } if (strlen($DATASOURCES[$this->cdr_source]['enableThor'])) { $this->enableThor = $DATASOURCES[$this->cdr_source]['enableThor']; } if ($this->enableThor) { require("/etc/cdrtool/ngnpro_engines.inc"); require_once("ngnpro_soap_library.php"); if ($DATASOURCES[$this->cdr_source]['soapEngineId'] && in_array($DATASOURCES[$this->cdr_source]['soapEngineId'], array_keys($soapEngines))) { $this->soapEngineId=$DATASOURCES[$this->cdr_source]['soapEngineId']; $this->SOAPlogin = array( "username" => $soapEngines[$this->soapEngineId]['username'], "password" => $soapEngines[$this->soapEngineId]['password'], "admin" => true ); $this->SOAPurl=$soapEngines[$this->soapEngineId]['url']; $this->SoapAuth = array('auth', $this->SOAPlogin , 'urn:AGProjects:NGNPro', 0, ''); // Instantiate the SOAP client $this->soapclient = new WebService_NGNPro_SipPort($this->SOAPurl); $this->soapclient->setOpt('curl', CURLOPT_TIMEOUT, 5); $this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0); $this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0); } else { print "Error: soapEngineID not defined in datasource $this->cdr_source"; return false; } } else { if ($DATASOURCES[$this->cdr_source]['table']) { $this->table = $DATASOURCES[$this->cdr_source]['table']; } $db_class = $DATASOURCES[$this->cdr_source]['db_class']; if (class_exists($db_class)) { $this->db = new $db_class; } else { printf("

Error: database class %s is not defined in datasource %s", $db_class, $this->cdr_source); return false; } } } private function getTrace($proxyIP, $callid, $fromtag, $totag) { if ($this->enableThor) { // get trace using soap request if (!$proxyIP || !$callid || !$fromtag) { echo "

Error: proxyIP or callid or fromtag are not defined

"; return false; } if (!is_object($this->soapclient)) { print "

Error: soap client is not defined"; return false; } $filter = array( 'nodeIp' => $proxyIP, 'callId' => $callid, 'fromTag' => $fromtag, 'toTag' => $totag ); $this->soapclient->addHeader($this->SoapAuth); $result = $this->soapclient->getMediaTrace($filter); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault = $result->getFault(); $error_code = $result->getCode(); if ($error_fault->detail->exception->errorcode != 1060) { printf( "

Error from %s


%s (%s)
", $this->SOAPurl, $error_fault->detail->exception->errorstring, $error_fault->detail->exception->errorcode ); } return false; } $this->info = json_decode($result); } else { if (!is_object($this->db)) { print "

Error: no database connection defined"; return false; } // get trace from SQL $query = sprintf( "select info from %s where call_id = '%s' and from_tag = '%s' and to_tag= '%s'", addslashes($this->table), addslashes($callid), addslashes($fromtag), addslashes($totag) ); if (!$this->db->query($query)) { printf( "

Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); return false; } if ($this->db->num_rows()) { $this->db->next_record(); $this->info = json_decode($this->db->f('info')); } } } public function show($proxyIP, $callid, $fromtag, $totag) { if ($_SERVER['HTTPS'] == "on") { $protocolURL = "https://"; } else { $protocolURL = "http://"; } $this->getTrace($proxyIP, $callid, $fromtag, $totag); if (!is_object($this->info)) { echo "

No information available
"; return false; } if (!count($this->info->streams)) { echo "
No RTP media streams have been established
"; return; } print "
"; $sessionId = rtrim(base64_encode(hash('md5', $callid, true)), "="); print "

CDRTool Media Trace
Call ID: $callid
Media Session ID: $sessionId

"; foreach (array_values($this->info->streams) as $_val) { $_diff=$_val->end_time-$_val->timeout_wait; $seen_stamp[$_val->start_time]++; $seen_stamp[$_val->end_time]++; $seen_stamp[$_diff]++; $media_types[]=$_val->media_type; } print "

Media Information

"; print ""; printf("", $this->info->duration); list($relay_ip, $relay_port)=explode(":", $this->info->streams[0]->caller_local); printf("", $relay_ip); print "
Call duration%s
Media relay%s
"; print "

Media Streams

"; print ""; print ""; foreach (array_values($media_types) as $_type) { printf("", ucfirst($_type)); } print ""; foreach ($this->info->streams[0] as $_val => $_value) { printf("", ucfirst(preg_replace("/_/", " ", $_val))); $j=0; while ($j < count($media_types)) { printf("", $this->info->streams[$j]->$_val); $j++; } printf("\n"); } print "
%s
%s%s
"; print "

Stream Succession

"; $w_legend_bar = 500; $w_text = 30; $stamps = array_keys($seen_stamp); sort($stamps); $w_table = $w_legend_bar + $w_text; print ""; $j = 0; $_index = 0; foreach (array_values($this->info->streams) as $_val) { if ($_val->status == 'unselected ice candidate') { continue; } $_index = $_index+$_val->start_time; $_duration = $_val->end_time-$_val->start_time; $_timeout = $_val->timeout_wait; $duration_print = $_duration; if ($_val->status == 'conntrack timeout') { $w_duration = intval(($_duration-$_timeout)*$w_legend_bar/$this->info->duration); $w_timeout = intval($_timeout*$w_legend_bar/$this->info->duration); $duration_print = $_duration - $_timeout; } elseif ($_val->status == 'no-traffic timeout') { $w_duration = intval($_duration*$w_legend_bar/$this->info->duration); $w_timeout = intval($_timeout*$w_legend_bar/$this->info->duration); } elseif ($_val->status == 'closed') { $w_duration = intval($_duration * $w_legend_bar / $this->info->duration); $w_timeout = 0; } $w_start_time = intval($_index*$w_legend_bar/$this->info->duration); $w_rest = $w_legend_bar-$w_duration-$w_timeout-$w_start_time; $w_duration_p = ($w_legend_bar/$w_duration) * 100; $w_timeout = 0; if ($w_timeout > 0) { $w_timeout_p = ($w_legend_bar/$w_timeout) * 100; } $w_start_p = 0; if ($w_start_time > 0) { $w_start_p = ($w_legend_bar/$w_start_time)* 100; } //printf ("%s, %s, %s, %s
\n",$w_start_p,$w_duration_p,$w_timeout_p,$w_rest); if ($_val->caller_packets != '0' && $_val->callee_packets != '0') { print ""; print ""; } elseif ($_val->status == 'unselected ICE candidate') { print ""; } else { print ""; } } print "
$_val->media_type\n"; //print "\n"; print "
"; print "
\n"; print "
$duration_print
\n"; if ($_val->timeout_wait) { print "
$_timeout
\n"; } else { print "
\n"; } //print "
\n"; //print "
\n"; print "
ICE session
No stream data found
"; print "
Legend"; print "

Session data
Timeout period

"; } } include_once "phone_images.php"; function getImageForUserAgent($msg) { global $userAgentImages; $msg_lines = explode("\n", $msg); foreach ($msg_lines as $line) { $els = explode(":", $line); if (strtolower($els[0]) == 'user-agent' || strtolower($els[0]) == 'server') { foreach ($userAgentImages as $agentRegexp => $image) { if (preg_match("/^(user-agent|server):.*$agentRegexp/i", $line)) { return $image; } } } } return "unknown.png"; } function isThorNode($ip, $sip_proxy) { if (!$ip || !$sip_proxy) { return false; } $socket = fsockopen($sip_proxy, 9500, $errno, $errstr, 1); if (!$socket) { return false; } $request=sprintf("is_online %s as sip_proxy", $ip); if (fputs($socket, "$request\r\n") !== false) { $ret = trim(fgets($socket, 4096)); fclose($socket); } else { fclose($socket); return false; } if ($ret == 'Yes') { return true; } else { return false; } } ?> diff --git a/library/rating.php b/library/rating.php index b2dd7fa..dca8414 100644 --- a/library/rating.php +++ b/library/rating.php @@ -1,10709 +1,9574 @@ db = $db; $this->settings = $settings; if ($this->database_backend == "mysql") { $this->db->Halt_On_Error="no"; } if ($this->settings['priceDenominator']) { $this->priceDenominator = $this->settings['priceDenominator']; } if ($this->settings['priceDecimalDigits']) { $this->priceDecimalDigits = $this->settings['priceDecimalDigits']; } if ($this->settings['durationPeriodRated']) { $this->durationPeriodRated = $this->settings['durationPeriodRated']; } if ($this->settings['trafficSizeRated']) { $this->trafficSizeRated = $this->settings['trafficSizeRated']; } if ($this->settings['rate_longer_than']) { // if call is shorter than this, it has zero cost $this->rate_longer_than = $this->settings['rate_longer_than']; } if ($this->settings['min_duration']) { // if call is shorter than this, it has zero cost $this->min_duration = $this->settings['min_duration']; } if ($this->settings['increment']) { $this->increment = $this->settings['increment']; } if ($this->settings['database_backend']) { $this->database_backend = $this->settings['database_backend']; } - if ($this->database_backend == "mongo") { - if (is_array($this->settings['mongo_db'])) { - $mongo_uri = $this->settings['mongo_db']['uri']; - $mongo_replicaSet = $this->settings['mongo_db']['replicaSet']; - $mongo_database = $this->settings['mongo_db']['database']; - try { - $mongo_connection = new Mongo("mongodb://$mongo_uri?readPreference=secondaryPreferred", array("replicaSet" => $mongo_replicaSet)); - $this->mongo_db = $mongo_connection->selectDB($mongo_database); - } catch (Exception $e) { - $log = sprintf("Error: cannot connect to mongo database %s: %s", $mongo_uri, $e->getMessage()); - syslog(LOG_NOTICE, $log); - $this->mongo_db = null; - } - } - } } public function calculateAudio($dictionary) { // used for calculate rate for audio application $this->RatingTables = $dictionary['RatingTables']; $this->callId = $dictionary['callId']; $this->timestamp = $dictionary['timestamp']; $this->duration = $dictionary['duration']; $this->traffic = 2 * ($dictionary['inputTraffic'] + $dictionary['outputTraffic']); $this->DestinationId = $dictionary['DestinationId']; $this->BillingPartyId = $dictionary['BillingPartyId']; $this->domain = $dictionary['domain']; $this->gateway = $dictionary['gateway']; $this->ResellerId = $dictionary['ResellerId']; $this->aNumber = $dictionary['aNumber']; $this->cNumber = $dictionary['cNumber']; $this->ENUMtld = $dictionary['ENUMtld']; if ($this->rate_longer_than && $this->duration < $this->rate_longer_than) { //syslog(LOG_NOTICE, "Duration less than minimum $this->rate_longer_than"); $this->rateInfo .= " Duration < $this->rate_longer_than s\n"; return true; } if ($this->ENUMtld && $this->ENUMtld != 'n/a' && $this->ENUMtld != 'none' && $this->RatingTables->ENUMtlds[$this->ENUMtld]) { $this->ENUMdiscount = $this->RatingTables->ENUMtlds[$this->ENUMtld]['discount']; if (!is_numeric($this->ENUMdiscount) || $this->ENUMdiscount < 0 || $this->ENUMdiscount > 100) { syslog(LOG_NOTICE, "Error: ENUM discount for tld $this->ENUMtld must be between 0 and 100"); } } if (!$this->gateway) { $this->gateway = "0.0.0.0"; } if (!$this->duration) { $this->duration = 0; } if (!$this->traffic) { $this->traffic = 0; } $this->application=$dictionary['application']; if (!$this->application) { $this->application = 'audio'; } $durationRate = 0; $foundRates = array(); if (!$this->DestinationId) { syslog(LOG_NOTICE, "Error: Cannot calculate rate without destination id for callid=$this->callId"); return false; } if (!$this->lookupDestinationDetails()) { // get region, increment and other per destination details syslog(LOG_NOTICE, "Error: Cannot find destination details for call_id=$this->callId, dest_id=$this->DestinationId)"); return false; } if (!$this->lookupProfiles()) { // get profiles for the billing party syslog(LOG_NOTICE, "Error: Cannot find any profiles for call_id=$this->callId, dest_id=$this->DestinationId)"); return false; } // lookup discounts if any $this->lookupDiscounts(); $this->startTimeBilling = getLocalTime($this->billingTimezone, $this->timestamp); list($dateText,$timeText) = explode(" ", trim($this->startTimeBilling)); $Bdate = explode("-", $dateText); $Btime = explode(":", $timeText); $this->timestampBilling = mktime($Btime[0], $Btime[1], $Btime[2], $Bdate[1], $Bdate[2], $Bdate[0]); $this->startTimeBilling = Date("Y-m-d H:i:s", $this->timestampBilling); $this->trafficKB = number_format($this->traffic/1024, 0, "", ""); // check min_duration and increment per destination if ($this->increment >= 1) { // increase the billed duration to the next increment $this->duration = $this->increment * ceil($this->duration / $this->increment); } if ($this->max_duration && $this->duration > $this->max_duration) { // limit the maximum duration for rating $this->duration = $this->max_duration; } $this->rateSyslog = ""; if ($this->duration) { if ($this->increment >= 1) { $this->rateInfo .= " Increment: $this->increment s\n"; $this->rateSyslog .= sprintf("Increment=%s ", $this->increment); } if ($this->min_duration) { $this->rateInfo .= " Min duration: $this->min_duration s\n"; $this->rateSyslog .= sprintf("MinDuration=%s ", $this->min_duration); } if ($this->max_duration) { $this->rateInfo .= " Max duration: $this->max_duration s\n"; $this->rateSyslog .= sprintf("MaxDuration=%s ", $this->max_duration); } if ($this->max_price) { $this->rateInfo .= " Max price: $this->max_price\n"; $this->rateSyslog .= sprintf("MaxPrice=%s ", $this->max_price); } unset($IntervalsForPricing); $this->rateInfo .= " Duration: $this->duration s\n". " App: $this->application\n". " Destination: $this->DestinationId\n". " Customer: $this->CustomerProfile\n"; if ($this->region) { $this->rateInfo .= " Region: $this->region\n"; } if ($this->discount_duration || $this->discount_connect) { $this->rateInfo .= " Discount: "; } if ($this->discount_connect) { $this->rateInfo .= " connect $this->discount_connect% "; } if ($this->discount_duration) { $this->rateInfo .= " duration $this->discount_duration% "; } if ($this->discount_duration || $this->discount_connect) { $this->rateInfo .= "\n"; } if ($this->ENUMtld && $this->ENUMtld != 'none' && $this->ENUMtld != 'n/a') { $this->rateInfo .= " ENUM tld: $this->ENUMtld\n". " ENUM discount: $this->ENUMdiscount%\n"; } $i=0; $durationRatedTotal=0; // get recursively a set of arrays with rates // until we billed the whole duration while ($durationRatedTotal < $this->duration) { if ($i == "0") { $dayofweek = date("w", $this->timestampBilling); $hourofday = date("G", $this->timestampBilling); $dayofyear = date("Y-m-d", $this->timestampBilling); } else { $dayofweek = date("w", $this->timestampBilling+$durationRatedTotal); $hourofday = $foundRate['nextHourOfDay']; $dayofyear = date("Y-m-d", $this->timestampBilling+$durationRatedTotal); } $foundRate = $this->lookupRateAudio($dayofyear, $dayofweek, $hourofday, $durationRatedTotal); $durationRatedTotal = $durationRatedTotal + $foundRate['duration']; if (!$foundRate['rate']) { $this->broken_rate=true; return false; } $foundRates[] = $foundRate; $i++; if ($i > 10) { // possible loop because of wrong coding make sure we end this loop somehow $body="Rating of call $this->callId (DestId=$this->DestinationId) has more than 10 spans. It could be a serious bug.\n"; mail($this->toEmail, "CDRTool rating problem", $body, $this->extraHeaders); syslog(LOG_NOTICE, "Error: Rating of call $this->callId (DestId=$this->DestinationId) has more than 10 spans."); break; } } } $j = 0; $span = 0; foreach ($foundRates as $thisRate) { $spanPrice = 0; $span++; if ($j > 0) { $payConnect = 0; $durationForRating = $thisRate['duration']; } else { $payConnect=1; if ($this->min_duration && $this->duration < $this->min_duration) { $durationForRating = $this->min_duration; } else { $durationForRating = $thisRate['duration']; } } $connectCost = $thisRate['values']['connectCost']; $durationRate = $thisRate['values']['durationRate']; // apply discounts for connect if ($this->discount_connect) { $connectCost = $connectCost - $connectCost * $this->discount_connect / 100; } // apply discounts for duration if ($this->discount_duration) { $durationRate = $durationRate - $durationRate * $this->discount_duration / 100; } $connectCostIn = $thisRate['values']['connectCostIn']; $durationRateIn = $thisRate['values']['durationRateIn']; if ($span=="1") { $connectCostSpan = $connectCost; $this->connectCost = number_format($connectCost/$this->priceDenominator, $this->priceDecimalDigits); $connectCostSpanIn = $connectCostIn; $this->connectCostIn = number_format($connectCostIn/$this->priceDenominator, $this->priceDecimalDigits); } else { $connectCostSpan=0; $connectCostSpanIn=0; } $connectCostPrint = number_format($connectCostSpan/$this->priceDenominator, $this->priceDecimalDigits); $durationRatePrint = number_format($durationRate/$this->priceDenominator, $this->priceDecimalDigits); $connectCostPrintIn = number_format($connectCostSpanIn/$this->priceDenominator, $this->priceDecimalDigits); $durationRatePrintIn = number_format($durationRateIn/$this->priceDenominator, $this->priceDecimalDigits); if (!$connectCostSpan) $connectCostSpan=0; if (!$durationRate) $durationRate=0; if (!$connectCostSpanIn) $connectCostSpanIn=0; if (!$durationRateIn) $durationRateIn=0; if (!$this->inputTraffic) $this->inputTraffic=0; if (!$this->outputTraffic) $this->outputTraffic=0; if ($span>1) $this->rateInfo .= "--\n"; /* durationRate*durationForRating/durationPeriodRated/priceDenominator+ trafficRate/priceDenominator/trafficSizeRated*(inputTraffic+outputTraffic)/8"); $durationRate*$durationForRating/$this->durationPeriodRated/$this->priceDenominator+ $trafficRate/$this->priceDenominator/$this->trafficSizeRated*($this->inputTraffic+$this->outputTraffic)/8"); */ $spanPrice = $durationRate * $durationForRating / $this->durationPeriodRated / $this->priceDenominator; $this->price = $this->price+$spanPrice; $spanPricePrint = number_format($spanPrice, $this->priceDecimalDigits); $spanPriceIn = $durationRateIn * $durationForRating / $this->durationPeriodRated / $this->priceDenominator; $this->priceIn = $this->priceIn+$spanPriceIn; $spanPricePrintIn = number_format($spanPriceIn, $this->priceDecimalDigits); if ($span=="1" && $thisRate['profile']) { if ($connectCostIn) { $this->rateInfo .= " Connect in: $connectCostPrintIn\n"; } $this->rateInfo .= " Connect: $connectCostPrint\n". " StartTime: $this->startTimeBilling\n". "--\n"; $this->rateSyslog .= "ConnectFee=$connectCostPrint "; $this->price = $this->price + $connectCostSpan / $this->priceDenominator * $payConnect; $this->priceIn = $this->priceIn + $connectCostSpanIn / $this->priceDenominator * $payConnect; } $this->rateInfo .= " Span: $span\n". " Duration: $durationForRating s\n"; $this->rateSyslog .= sprintf( "CallId=%s Span=%s Duration=%s DestId=%s %s", $this->callId, $span, $durationForRating, $this->DestinationId, $thisRate['customer'] ); if ($thisRate['profile']) { $this->rateInfo .= " ProfileId: $thisRate[profile] / $thisRate[day]\n". " RateId: $thisRate[rate] / $thisRate[interval]h\n". " Rate: $durationRatePrint / $this->durationPeriodRated s\n". " Price: $spanPricePrint\n"; if ($spanPriceIn) { $this->rateInfo .= " Price in: $spanPricePrintIn\n"; } $this->rateSyslog .= sprintf( " Profile=%s Period=%s Rate=%s Interval=%s Cost=%s/%s", $thisRate['profile'], $thisRate['day'], $thisRate['rate'], $thisRate['interval'], $durationRatePrint, $this->durationPeriodRated ); } else { $this->rateInfo .= " ProfileId: none\n". " RateId: none\n"; $this->rateSyslog .= " Profile=none, Rate=none"; } $this->rateSyslog .= " Price=".sprintf("%.4f", $spanPrice); $this->rateSyslog .= " PriceIn=".sprintf("%.4f", $spanPriceIn); if ($this->discount_connect) { $this->rateSyslog .= sprintf(" DisCon=%s", $this->discount_connect); } if ($this->discount_duration) { $this->rateSyslog .= sprintf(" DisDur=%s", $this->discount_duration); } syslog(LOG_NOTICE, $this->rateSyslog); $j++; } if ($this->priceIn) { $this->rateInfo .= "--\n". " Price out: ".sprintf("%.4f", $this->price)."\n". " Price in: ".sprintf("%.4f", $this->priceIn)."\n". " Margin: ".sprintf("%.4f", $this->price-$this->priceIn)."\n"; } $this->rateInfo=trim($this->rateInfo); if ($this->max_price && $this->price > $this->max_price) { $this->price = $this->max_price; } if ($this->ENUMdiscount) { $this->priceBeforeDiscount = sprintf("%.4f", $this->price); $this->price = $this->price - $this->price * $this->ENUMdiscount / 100; $this->price = sprintf("%.4f", $this->price); $this->rateInfo .= "\n--\n". " Total: $this->priceBeforeDiscount\n". " Total after discount: $this->price\n"; } $this->price = sprintf("%.4f", $this->price); $this->pricePrint = number_format($this->price, $this->priceDecimalDigits); return true; } public function calculateMessage($dictionary) { // used for calculate rate for SMS application $this->RatingTables = $dictionary['RatingTables']; $this->callId = $dictionary['callId']; $this->timestamp = $dictionary['timestamp']; $this->DestinationId = $dictionary['DestinationId']; $this->BillingPartyId = $dictionary['BillingPartyId']; $this->domain = $dictionary['domain']; $this->gateway = $dictionary['gateway']; $this->ResellerId = $dictionary['ResellerId']; $this->aNumber = $dictionary['aNumber']; $this->cNumber = $dictionary['cNumber']; if (!$this->gateway) { $this->gateway = "0.0.0.0"; } $this->application = 'sms'; $foundRates=array(); if (!$this->DestinationId) { syslog(LOG_NOTICE, "Error calculateMessage(): Cannot calculate rate without destination id"); return false; } if (!$this->lookupProfiles()) { // get profiles for the billing party syslog(LOG_NOTICE, "Error: calculateMessage() Cannot find any profiles for call_id=$this->callId, dest_id=$this->DestinationId)"); return false; } // lookup discounts if any $this->lookupDiscounts(); $this->startTimeBilling = getLocalTime($this->billingTimezone, $this->timestamp); list($dateText,$timeText) = explode(" ", trim($this->startTimeBilling)); $Bdate = explode("-", $dateText); $Btime = explode(":", $timeText); $this->timestampBilling = mktime($Btime[0], $Btime[1], $Btime[2], $Bdate[1], $Bdate[2], $Bdate[0]); $dayofweek = date("w", $this->timestampBilling); $hourofday = date("G", $this->timestampBilling); $dayofyear = date("Y-m-d", $this->timestampBilling); $this->rateInfo .= " App: sms\n". " Destination: $this->DestinationId\n". " Customer: $this->CustomerProfile\n"; if ($this->region) { $this->rateInfo .= " Region: $this->region\n"; } if ($this->discount_duration || $this->discount_connect) { $this->rateInfo .= " Discount: "; } if ($this->discount_connect) { $this->rateInfo .= " connect $this->discount_connect% "; } if ($this->discount_duration || $this->discount_connect) { $this->rateInfo .= "\n"; } $foundRate = $this->lookupRateMessage($dayofyear, $dayofweek, $hourofday); if (is_array($foundRate)) { $this->price = number_format($foundRate['values']['connectCost'] / $this->priceDenominator, $this->priceDecimalDigits); $this->price = sprintf("%.4f", $this->price); $this->pricePrint = $this->price; $this->rateInfo .= " ProfileId: $foundRate[profile] / $foundRate[day]\n". " RateId: $foundRate[rate]\n". " Price: $this->price\n"; return true; } else { return false; } } private function lookupDiscounts() { // get discounts for customer per region if set otherwise per destination id if (!$this->CustomerProfile) { return false; } if ($this->region) { $_field = 'region'; $_value = $this->region; } else { $_field = 'destination'; $_value = $this->DestinationId; } - if ($this->mongo_db != null) { - // mongo backend - if ($this->CustomerProfile == 'default') { - $mongo_where['subscriber'] = ''; - $mongo_where['domain'] = ''; - $mongo_where['domain'] = ''; - $mongo_where['domain'] = ''; - $mongo_where['application'] = $this->application; - $mongo_where[$_field] = $_value; - } else { - $els = explode("=", $this->CustomerProfile); - $mongo_where[$els[0]] = $els[1]; - $mongo_where['application'] = $this->application; - $mongo_where[$_field] = $_value; - } - - try { - $table = $this->mongo_db->selectCollection('billing_discounts'); - $cursor = $table->find($mongo_where)->limit(1)->slaveOkay(); - $result = $cursor->getNext(); - } catch (Exception $e) { - $log = sprintf("

Caught exception in lookupDiscounts(): %s", $e->getMessage()); - syslog(LOG_NOTICE, $log); - return false; - } - - if ($result) { - if ($result['connect'] > 0 && $result['connect'] <=100) { - $this->discount_connect = $result['connect']; - } - - if ($result['duration'] > 0 && $result['duration'] <=100) { - $this->discount_duration = $result['duration']; - } - return true; - } - } - if ($this->CustomerProfile == 'default') { $query = sprintf( "select * from billing_discounts where subscriber = '' and domain = '' and gateway = '' and application = '%s' and %s = '%s' ", addslashes($this->application), addslashes($_field), addslashes($_value) ); } else { $els = explode("=", $this->CustomerProfile); $query = sprintf( "select * from billing_discounts where %s = '%s' and application = '%s' and %s = '%s' ", addslashes($els[0]), addslashes($els[1]), addslashes($this->application), addslashes($_field), addslashes($_value) ); } // mysql backend if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return false; } if ($this->db->num_rows()) { $this->db->next_record(); if ($this->db->f('connect') > 0 && $this->db->f('connect') <=100) { $this->discount_connect = $this->db->f('connect'); } if ($this->db->f('duration') > 0 && $this->db->f('duration') <=100) { $this->discount_duration = $this->db->f('duration'); } } return true; } private function lookupDestinationDetails() { // get rating related details for the destination id if (!$this->DestinationId) { syslog(LOG_NOTICE, "Error: Cannot lookup destination details without a destination id"); return false; } - if ($this->mongo_db != null) { - // mongo backend - $mongo_where['dest_id'] = $this->DestinationId; - $mongo_where['$or'] = array( - array( - 'reseller_id' => intval($this->ResellerId) - ), - array('reseller_id' => 0) - ); - - try { - $table = $this->mongo_db->selectCollection('destinations'); - $cursor = $table->find($mongo_where)->sort(array('reseller_id'=>-1))->limit(1)->slaveOkay(); - $result = $cursor->getNext(); - } catch (Exception $e) { - $log = sprintf("

Caught exception in lookupProfiles(): %s", $e->getMessage()); - syslog(LOG_NOTICE, $log); - return false; - } - - if (!$result) { - $log = sprintf("Error: cannot find mongo destination details for dest id %s", $this->DestinationId); - syslog(LOG_NOTICE, $log); - //return false; - } - - if ($result) { - $this->region = $result['region']; - $this->max_duration = $result['max_duration']; - $this->max_price = $result['max_price']; - - if ($result['increment']) { - $this->increment = $result['increment']; - } - - if ($result['min_duration']) { - $this->min_duration = $result['min_duration']; - } - return true; - } - } - // mysql backend $query = sprintf( "select * from destinations where dest_id = '%s' and (reseller_id = %d or reseller_id = 0) order by reseller_id desc limit 1 ", addslashes($this->DestinationId), addslashes($this->ResellerId) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return false; } if ($this->db->num_rows()) { $this->db->next_record(); $this->region = $this->db->Record['region']; $this->max_duration = $this->db->Record['max_duration']; $this->max_price = $this->db->Record['max_price']; if ($this->db->Record['increment']) { $this->increment = $this->db->Record['increment']; } if ($this->db->Record['min_duration']) { $this->min_duration = $this->db->Record['min_duration']; } } return true; } private function lookupProfiles() { unset($this->allProfiles); /* lookup the profile_name in billing_customers in the following order: subscriber, domain, gateway (based on $dayofweek): - profile_workday matches days [1-5] (Work-day) - profile_weekend matches days [6-0] (Week-end) - week starts with 0 Sunday and ends with 6 Saturday Alternatively look for profile_workday_alt and profile_weekend_alt If no rates are found for destination in the profileX, than lookup rates in profileX_alt */ - if ($this->mongo_db != null) { - // mongo backend - - $mongo_where['$or'] = array( - array('subscriber' => $this->BillingPartyId), - array('domain' => $this->domain), - array('gateway' => $this->gateway), - array( - 'gateway' => '', - 'domain' => '', - 'subscriber' => '' - ) - ); - - try { - $table = $this->mongo_db->selectCollection('billing_customers'); - $cursor = $table->find($mongo_where)->sort(array('subscriber'=>-1, 'domain'=>-1, 'gateway'=>-1))->limit(1)->slaveOkay(); - $result = $cursor->getNext(); - } catch (Exception $e) { - $log = sprintf("

Caught exception in lookupProfiles(): %s", $e->getMessage()); - syslog(LOG_NOTICE, $log); - return false; - } - - if (!$result) { - $log = sprintf( - "Error: no customer found in mongo billing_customers table for billing party=%s, domain=%s, gateway=%s", - $this->BillingPartyId, - $this->domain, - $this->gateway - ); - syslog(LOG_NOTICE, $log); - //return false; - } - - if ($result) { - if ($result['subscriber']) { - $this->CustomerProfile = sprintf("subscriber=%s", $result['subscriber']); - } elseif ($result['domain']) { - $this->CustomerProfile = sprintf("domain=%s", $result['domain']); - } elseif ($result['gateway']) { - $this->CustomerProfile = sprintf("gateway=%s", $result['gateway']); - } else { - $this->CustomerProfile = "default"; - } - - if (!$result['profile_name1']) { - $log = sprintf( - "Error: customer %s (id=%d) has no weekday profile assigned in profiles table", - $this->CustomerProfile, - $result['id'] - ); - syslog(LOG_NOTICE, $log); - return false; - } - - if (!$result['profile_name2']) { - $log = sprintf( - "Error: customer %s (id=%d) has no weekend profile assigned in profiles table", - $this->CustomerProfile, - $result['id'] - ); - syslog(LOG_NOTICE, $log); - return false; - } - - - if (!$result['timezone']) { - $log = sprintf( - "Error: missing timezone for customer %s", - $this->CustomerProfile - ); - syslog(LOG_NOTICE, $log); - return false; - } - - $this->billingTimezone = $result['timezone']; - - $this->allProfiles = array( - "profile_workday" => $result['profile_name1'], - "profile_weekend" => $result['profile_name2'], - "profile_workday_alt" => $result['profile_name1_alt'], - "profile_weekend_alt" => $result['profile_name2_alt'], - "timezone" => $result['timezone'] - ); - if ($result['increment']) { - $this->increment = $result['increment']; - } - - if ($result['min_duration']) { - $this->min_duration = $result['min_duration']; - } - return true; - } - } - // mysql backend $query = sprintf( "select * from billing_customers where (subscriber = '%s' and domain = '' and gateway = '' ) or (domain = '%s' and subscriber = '' and gateway = '' ) or (gateway = '%s' and subscriber = '' and domain = '' ) or (subscriber = '' and domain = '' and gateway = '' ) order by subscriber desc, domain desc, gateway desc limit 1 ", addslashes($this->BillingPartyId), addslashes($this->domain), addslashes($this->gateway) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return false; } if ($this->db->num_rows()) { $this->db->next_record(); if ($this->db->Record['subscriber']) { $this->CustomerProfile = sprintf("subscriber=%s", $this->db->Record['subscriber']); } elseif ($this->db->Record['domain']) { $this->CustomerProfile = sprintf("domain=%s", $this->db->Record['domain']); } elseif ($this->db->Record['gateway']) { $this->CustomerProfile = sprintf("gateway=%s", $this->db->Record['gateway']); } else { $this->CustomerProfile = "default"; } if (!$this->db->Record['profile_name1']) { $log = sprintf( "Error: customer %s (id=%d) has no weekday profile assigned in profiles table", $this->CustomerProfile, $this->db->Record['id'] ); syslog(LOG_NOTICE, $log); return false; } if (!$this->db->Record['profile_name2']) { $log = sprintf( "Error: customer %s (id=%d) has no weekend profile assigned in profiles table", $this->CustomerProfile, $this->db->Record['id'] ); syslog(LOG_NOTICE, $log); return false; } if (!$this->db->Record['timezone']) { $log = sprintf( "Error: missing timezone for customer %s", $this->CustomerProfile ); syslog(LOG_NOTICE, $log); return false; } $this->billingTimezone = $this->db->Record['timezone']; $this->allProfiles = array( "profile_workday" => $this->db->Record['profile_name1'], "profile_weekend" => $this->db->Record['profile_name2'], "profile_workday_alt" => $this->db->Record['profile_name1_alt'], "profile_weekend_alt" => $this->db->Record['profile_name2_alt'], "timezone" => $this->db->Record['timezone'] ); if ($this->db->Record['increment']) { $this->increment = $this->db->Record['increment']; } if ($this->db->Record['min_duration']) { $this->min_duration = $this->db->Record['min_duration']; } return true; } else { $log = sprintf( "Error: no customer found in billing_customers table for billing party=%s, domain=%s, gateway=%s", $this->BillingPartyId, $this->domain, $this->gateway ); syslog(LOG_NOTICE, $log); return false; } } private function lookupRateAudio($dayofyear, $dayofweek, $hourofday, $durationRatedAlready) { /* // Required information from CDR structure $this->BillingPartyId # calling subscriber $this->domain # multiple callers may belong to same domain $this->gateway # multiple callers may belong to the same gateway $this->cNumber # E164 destination prefixed with 00 (e.g. 0041 CH) $this->DestinationId # longest matched DestinationId $this->region # region the destination belongs to // pertinent to the curent rating SPAN (a span = same profile like evening hours) $hourofday # which hour of teh day started for peak/ofpeak rates $dayofweek # which day of the week for matching profiles $dayofyear # which day of the year for matching holidays $durationRatedAlready= the full duration for which a profile is defined (e.g. 0800-1800) // the call is called recursively until the $durationRatedAlready = $CDR->duration // when a call spans multiple profiles. If we span multiple profiles we must call // the function again to lookup the corect rates Rating logic ------------ 1. using the profile_name found, lookup the rate_name based on $hourofday in billing_profiles - the day may be split in maximum 4 periods - each day starts with hour 0 and ends with hour 24 - rate_name1 defines the first interval after hour 0 - rate_name2 defines the first interval after rate_name1 - rate_name3 defines the first interval after rate_name2 - rate_name4 defines the first interval after rate_name3 When the hour matches an interval use the rate_nameX found to lookup the rate in billing_rates - if no record is found use the rate called 'default' 2. lookup in billing_rates the record having same name found above and billing_rates.destination = $this->DestinationId - return an array with all the values to $this->calculateAudio() function that called us */ // get work-day or weekend profile if ($this->RatingTables->holidays[$dayofyear]) { $this->profileName = $this->allProfiles['profile_weekend']; $this->profileNameAlt = $this->allProfiles['profile_weekend_alt']; $this->PeriodOfProfile = "weekend"; } else { if ($dayofweek >=1 && $dayofweek <=5) { $this->profileName = $this->allProfiles['profile_workday']; $this->profileNameAlt = $this->allProfiles['profile_workday_alt']; $this->PeriodOfProfile = "weekday"; } else { $this->profileName = $this->allProfiles['profile_weekend']; $this->profileNameAlt = $this->allProfiles['profile_weekend_alt']; $this->PeriodOfProfile = "weekend"; } } // get rate for the time of the day $timestampNextProfile = $this->timestampBilling + $durationRatedAlready; $profileValues = $this->RatingTables->profiles[$this->profileName]; if (is_array($profileValues)) { $this->profileNameLog = $this->profileName; if ($hourofday < $profileValues['hour1']) { $this->rateName = $profileValues['rate_name1']; $this->timeInterval = "0-".$profileValues['hour1']; $foundProfile = $profileValues['hour1']; $this->nextProfile = $profileValues['hour1']; } elseif ($hourofday < $profileValues['hour2']) { $this->rateName = $profileValues['rate_name2']; $this->timeInterval = $profileValues['hour1']."-".$profileValues['hour2']; $foundProfile = $profileValues['hour2']; $this->nextProfile = $profileValues['hour2']; } elseif ($hourofday < $profileValues['hour3']) { $this->rateName = $profileValues['rate_name3']; $this->timeInterval = $profileValues['hour2']."-".$profileValues['hour3']; $foundProfile = $profileValues['hour3']; $this->nextProfile = $profileValues['hour3']; } elseif ($hourofday < $profileValues['hour4']) { $this->rateName = $profileValues['rate_name4']; $this->timeInterval = $profileValues['hour3']."-".$profileValues['hour4']; $foundProfile = $profileValues['hour4']; $this->nextProfile = 0; } if ($this->rateName) { $found_history=false; //get historical rating if exists if (is_array($this->RatingTables->ratesHistory[$this->rateName][$this->DestinationId][$this->application])) { $h=0; foreach (($this->RatingTables->ratesHistory[$this->rateName][$this->DestinationId][$this->application]) as $_idx) { $h++; if ($_idx['startDate'] <= $this->timestamp) { if ($_idx['endDate'] > $this->timestamp) { // found historical rate $found_history=true; $this->rateValues=$_idx; break; } else { $_log = sprintf("Interval missmatch %s < %s", $_idx['endDate'], $this->timestamp); continue; } } else { $_log = sprintf("Interval missmatch %s > %s", $_idx['startDate'], $this->timestamp); continue; } } } if (!$found_history) { if ($this->region) { $this->rateValues = $this->lookupRateValuesAudio($this->rateName, $this->region); if (!$this->rateValues) { // try the destination as last resort $this->rateValues = $this->lookupRateValuesAudio($this->rateName, $this->DestinationId); } } else { $this->rateValues = $this->lookupRateValuesAudio($this->rateName, $this->DestinationId); } } } } $profileValuesAlt = $this->RatingTables->profiles[$this->profileNameAlt]; if (!$this->rateValues && is_array($profileValuesAlt)) { $this->profileNameLog = $this->profileNameAlt; if ($hourofday < $profileValuesAlt['hour1']) { $this->rateName = $profileValuesAlt['rate_name1']; $this->timeInterval = "0-".$profileValuesAlt['hour1']; $foundProfile = $profileValuesAlt['hour1']; $this->nextProfile = $profileValuesAlt['hour1']; } elseif ($hourofday < $profileValuesAlt['hour2']) { $this->rateName = $profileValuesAlt['rate_name2']; $this->timeInterval = $profileValuesAlt['hour1']."-".$profileValuesAlt['hour2']; $foundProfile = $profileValuesAlt['hour2']; $this->nextProfile = $profileValuesAlt['hour2']; } elseif ($hourofday < $profileValuesAlt['hour3']) { $this->rateName = $profileValuesAlt['rate_name3']; $this->timeInterval = $profileValuesAlt['hour2']."-".$profileValuesAlt['hour3']; $foundProfile = $profileValuesAlt['hour3']; $this->nextProfile = $profileValuesAlt['hour3']; } elseif ($hourofday < $profileValuesAlt['hour4']) { $this->rateName = $profileValuesAlt['rate_name4']; $this->timeInterval = $profileValuesAlt['hour3']."-".$profileValuesAlt['hour4']; $foundProfile = $profileValuesAlt['hour4']; $this->nextProfile = 0; } if ($this->rateName) { $found_history=false; //get historical rating if exists if (is_array($this->RatingTables->ratesHistory[$this->rateName][$this->DestinationId][$this->application])) { $h=0; foreach (($this->RatingTables->ratesHistory[$this->rateName][$this->DestinationId][$this->application]) as $_idx) { $h++; if ($_idx['startDate'] <= $this->timestamp) { if ($_idx['endDate'] > $this->timestamp) { // found historical rate $found_history=true; $this->rateValues=$_idx; break; } else { $_log = sprintf("Interval missmatch %s < %s", $_idx['endDate'], $this->timestamp); continue; } } else { $_log = sprintf("Interval missmatch %s > %s", $_idx['startDate'], $this->timestamp); continue; } } } if (!$found_history) { if ($this->region) { $this->rateValues = $this->lookupRateValuesAudio($this->rateName, $this->region); // try destination as last resort if (!$this->rateValues) { $this->rateValues = $this->lookupRateValuesAudio($this->rateName, $this->DestinationId); } } else { $this->rateValues = $this->lookupRateValuesAudio($this->rateName, $this->DestinationId); } } } } if (!$this->rateValues) { $this->rateNotFound=true; $log = sprintf( "Error: Cannot find rates for callid=%s, billing party=%s, customer %s, gateway=%s, destination=%s, profile=%s, app=%s", $this->callId, $this->BillingPartyId, $this->CustomerProfile, $this->gateway, $this->DestinationId, $this->profileName, $this->application ); syslog(LOG_NOTICE, $log); return false; } if ($this->nextProfile == "24") $this->nextProfile = 0; $DST = Date("I", $timestampNextProfile); if (!$this->nextProfile) { // check it we change daylight saving time tomorrow // yes this cann happen and we must apply a different rate $timestampNextProfile =$timestampNextProfile+24*3600; $DSTNext = Date("I", $timestampNextProfile); if ($DST != $DSTNext) { if ($DSTNext==0) { $timestampNextProfile = $timestampNextProfile+3600; } elseif ($DSTNext==1) { $timestampNextProfile = $timestampNextProfile-3600; } } } // see if we have minimum duration or increment if ($this->rateValues['increment']) { // increase the billed duration to the next increment $this->duration = $this->rateValues['increment'] * ceil($this->duration / $this->rateValues['increment']); } $durationToRate=$this->duration-$durationRatedAlready; $month = Date("m", $timestampNextProfile); $day = Date("d", $timestampNextProfile); $year = Date("Y", $timestampNextProfile); $nextProfileTimestamp = mktime($this->nextProfile, 0, 0, $month, $day, $year); $npdt=Date("Y-m-d H:i", $nextProfileTimestamp); $timeTillNextProfile = $nextProfileTimestamp - $this->timestampBilling; if ($durationToRate > $timeTillNextProfile) { $diff = $durationToRate - $timeTillNextProfile; $this->durationRated = $timeTillNextProfile; } else { $this->durationRated = $durationToRate; } $rate = array( "customer" => $this->CustomerProfile, "application" => $this->application, "profile" => $this->profileNameLog, "day" => $this->PeriodOfProfile, "destinationId" => $this->DestinationId, "duration" => $this->durationRated, "rate" => $this->rateName, "values" => $this->rateValues, "interval" => $this->timeInterval, "nextHourOfDay" => $this->nextProfile ); return $rate; } private function lookupRateMessage($dayofyear, $dayofweek, $hourofday) { /* // Required information from CDR structure $this->BillingPartyId # calling subscriber $this->domain # multiple callers may belong to same domain $this->gateway # multiple callers may belong to the same gateway $this->cNumber # E164 destination prefixed with 00 (e.g. 0041 CH) $this->DestinationId # longest matched DestinationId $this->region # region the destination belongs to // pertinent to the curent rating SPAN (a span = same profile like evening hours) $hourofday # which hour of teh day started for peak/ofpeak rates $dayofweek # which day of the week for matching profiles $dayofyear # which day of the year for matching holidays $durationRatedAlready= the full duration for which a profile is defined (e.g. 0800-1800) // the call is called recursively until the $durationRatedAlready = $CDR->duration // when a call spans multiple profiles. If we span multiple profiles we must call // the function again to lookup the corect rates Rating logic ------------ 1. using the profile_name found, lookup the rate_name based on $hourofday in billing_profiles - the day may be split in maximum 4 periods - each day starts with hour 0 and ends with hour 24 - rate_name1 defines the first interval after hour 0 - rate_name2 defines the first interval after rate_name1 - rate_name3 defines the first interval after rate_name2 - rate_name4 defines the first interval after rate_name3 When the hour matches an interval use the rate_nameX found to lookup the rate in billing_rates - if no record is found use the rate called 'default' 2. lookup in billing_rates the record having same name found above and billing_rates.destination = $this->DestinationId - return an array with all the values to $this->calculateAudio() function that called us */ // get work-day or weekend profile if ($this->RatingTables->holidays[$dayofyear]) { $this->profileName = $this->allProfiles['profile_weekend']; $this->profileNameAlt = $this->allProfiles['profile_weekend_alt']; $this->PeriodOfProfile = "weekend"; } else { if ($dayofweek >=1 && $dayofweek <=5) { $this->profileName = $this->allProfiles['profile_workday']; $this->profileNameAlt = $this->allProfiles['profile_workday_alt']; $this->PeriodOfProfile = "weekday"; } else { $this->profileName = $this->allProfiles['profile_weekend']; $this->profileNameAlt = $this->allProfiles['profile_weekend_alt']; $this->PeriodOfProfile = "weekend"; } } // get rate for the time of the day $timestampNextProfile = $this->timestampBilling + $durationRatedAlready; $profileValues = $this->RatingTables->profiles[$this->profileName]; if (is_array($profileValues)) { $this->profileNameLog = $this->profileName; if ($hourofday < $profileValues['hour1']) { $this->rateName = $profileValues['rate_name1']; $this->timeInterval = "0-".$profileValues['hour1']; $foundProfile = $profileValues['hour1']; } elseif ($hourofday < $profileValues['hour2']) { $this->rateName = $profileValues['rate_name2']; $this->timeInterval = $profileValues['hour1']."-".$profileValues['hour2']; $foundProfile = $profileValues['hour2']; } elseif ($hourofday < $profileValues['hour3']) { $this->rateName = $profileValues['rate_name3']; $this->timeInterval = $profileValues['hour2']."-".$profileValues['hour3']; $foundProfile = $profileValues['hour3']; } elseif ($hourofday < $profileValues['hour4']) { $this->rateName = $profileValues['rate_name4']; $this->timeInterval = $profileValues['hour3']."-".$profileValues['hour4']; $foundProfile = $profileValues['hour4']; } if ($this->rateName) { if ($this->region) { $this->rateValues=$this->lookupRateValuesMessage($this->rateName, $this->region); if (!$this->rateValues) { // try the destination as last resort $this->rateValues=$this->lookupRateValuesMessage($this->rateName, $this->DestinationId); } } else { $this->rateValues=$this->lookupRateValuesMessage($this->rateName, $this->DestinationId); } } } $profileValuesAlt = $this->RatingTables->profiles[$this->profileNameAlt]; if (!$this->rateValues && is_array($profileValuesAlt)) { $this->profileNameLog = $this->profileNameAlt; if ($hourofday < $profileValuesAlt['hour1']) { $this->rateName = $profileValuesAlt['rate_name1']; $this->timeInterval = "0-".$profileValuesAlt['hour1']; $foundProfile = $profileValuesAlt['hour1']; } elseif ($hourofday < $profileValuesAlt['hour2']) { $this->rateName = $profileValuesAlt['rate_name2']; $this->timeInterval = $profileValuesAlt['hour1']."-".$profileValuesAlt['hour2']; $foundProfile = $profileValuesAlt['hour2']; } elseif ($hourofday < $profileValuesAlt['hour3']) { $this->rateName = $profileValuesAlt['rate_name3']; $this->timeInterval = $profileValuesAlt['hour2']."-".$profileValuesAlt['hour3']; $foundProfile = $profileValuesAlt['hour3']; } elseif ($hourofday < $profileValuesAlt['hour4']) { $this->rateName = $profileValuesAlt['rate_name4']; $this->timeInterval = $profileValuesAlt['hour3']."-".$profileValuesAlt['hour4']; $foundProfile = $profileValuesAlt['hour4']; } if ($this->rateName) { if ($this->region) { $this->rateValues = $this->lookupRateValuesMessage($this->rateName, $this->region); // try destination as last resort if (!$this->rateValues) { $this->rateValues = $this->lookupRateValuesMessage($this->rateName, $this->DestinationId); } } else { $this->rateValues = $this->lookupRateValuesMessage($this->rateName, $this->DestinationId); } } } if (!$this->rateValues) { $this->rateNotFound=true; $log=sprintf( "Error: Cannot find rates for callid=%s, billing party=%s, customer %s, gateway=%s, destination=%s, profile=%s, app=sms", $this->callId, $this->BillingPartyId, $this->CustomerProfile, $this->gateway, $this->DestinationId, $this->profileName ); syslog(LOG_NOTICE, $log); return false; } $rate = array( "customer" => $this->CustomerProfile, "application" => $this->application, "profile" => $this->profileNameLog, "day" => $this->PeriodOfProfile, "destinationId" => $this->DestinationId, "rate" => $this->rateName, "values" => $this->rateValues, ); return $rate; } public function MaxSessionTime($dictionary) { // Used for prepaid application to return maximum session time based on a prepaid balance $this->rateValuesCache = array(); $this->MaxSessionTimeSpans = 0; $durationRate = 0; ///////////////////////////////////////////////////// // required fields passed from the CDR structure // $this->timestamp = time(); $this->callId = $dictionary['callId']; $this->DestinationId = $dictionary['DestinationId']; $this->BillingPartyId = $dictionary['BillingPartyId']; $this->domain = $dictionary['domain']; $this->duration = $dictionary['duration']; $this->aNumber = $dictionary['aNumber']; $this->cNumber = $dictionary['cNumber']; $this->gateway = $dictionary['gateway']; $this->RatingTables = $dictionary['RatingTables']; $this->application = $dictionary['application']; $this->ResellerId = $dictionary['ResellerId']; $Balance = $dictionary['Balance']; if (!$this->application) $this->application='audio'; if (!$this->DestinationId) { $log = sprintf("Error: no DestinationId supplied in MaxSessionTime()"); syslog(LOG_NOTICE, $log); return false; } if (!$this->lookupDestinationDetails()) { return false; } if (!$this->lookupProfiles()) { return false; } $this->startTimeBilling = getLocalTime($this->billingTimezone, $this->timestamp); list($dateText,$timeText) = explode(" ", trim($this->startTimeBilling)); $Bdate = explode("-", $dateText); $Btime = explode(":", $timeText); $this->timestampBilling = mktime($Btime[0], $Btime[1], $Btime[2], $Bdate[1], $Bdate[2], $Bdate[0]); $this->startTimeBilling = Date("Y-m-d H:i:s", $this->timestampBilling); $i=0; $durationRatedTotal=0; while ($Balance > 0) { $span++; $this->MaxSessionTimeSpans++; if ($i == "0") { $dayofweek = date("w", $this->timestampBilling); $hourofday = date("G", $this->timestampBilling); $dayofyear = date("Y-m-d", $this->timestampBilling); } else { $dayofweek = date("w", $this->timestampBilling+$durationRatedTotal); $hourofday = $foundRate['nextHourOfDay']; $dayofyear = date("Y-m-d", $this->timestampBilling+$durationRatedTotal); } $foundRate = $this->lookupRateAudio($dayofyear, $dayofweek, $hourofday, $durationRatedTotal); if ($this->rateNotFound) { // break here to avoid loops break; } $thisRate=$foundRate; if ($j > 0) { $payConnect=0; $durationForRating = $thisRate['duration']; } else { $payConnect=1; if ($this->min_duration && $this->duration < $this->min_duration) { $durationForRating=$this->min_duration; } else { $durationForRating=$thisRate['duration']; } } $j++; $connectCost = $thisRate['values']['connectCost']; $durationRate = $thisRate['values']['durationRate']; if ($span=="1" && !$dictionary['skipConnectCost']) { $this->connectCost=number_format($connectCost/$this->priceDenominator, $this->priceDecimalDigits); $connectCostSpan=$connectCost; $setupBalanceRequired=$connectCost/$this->priceDenominator; if ($connectCost && $Balance <= $setupBalanceRequired) { syslog(LOG_NOTICE, "Balance too small: $Balance <= $setupBalanceRequired"); return false; } $Balance = $Balance-$setupBalanceRequired; } else { $connectCostSpan=0; $setupBalanceRequired=0; } $connectCostPrint = number_format($connectCostSpan/$this->priceDenominator, $this->priceDecimalDigits); $durationRatePrint = number_format($durationRate/$this->priceDenominator, $this->priceDecimalDigits); $spanPrice = $this->price+$setupBalanceRequired*$payConnect+ $durationRate*$durationForRating/$this->durationPeriodRated/$this->priceDenominator; if ($Balance > $spanPrice) { $Balance = $Balance-$spanPrice; $durationRatedTotal = $durationRatedTotal+ $foundRate['duration']; } else { $durationAllowedinThisSpan = $Balance / $durationRate * $this->durationPeriodRated * $this->priceDenominator; $rateOfThisSpan=$durationRate/$this->priceDenominator; $durationRatedTotal=$durationRatedTotal + $durationAllowedinThisSpan; $Balance=$Balance-$spanPrice; return $durationRatedTotal; } if ($durationRatedTotal >= $this->duration) { return sprintf("%f", $durationRatedTotal); } $i++; if ($i>10) { return sprintf("%f", $durationRatedTotal); break; } } return false; } private function lookupRateValuesAudio($rateName, $DestinationId) { if (is_array($this->rateValuesCache[$rateName][$DestinationId][$this->application])) { return $this->rateValuesCache[$rateName][$DestinationId][$this->application]; } - if ($this->mongo_db != null) { - // mongo backend - $mongo_where['destination'] = $DestinationId; - $mongo_where['application'] = $this->application; - $mongo_where['$or'] = array( - array('reseller_id' => intval($this->ResellerId)), - array('reseller_id' => 0) - ); - - try { - $table = $this->mongo_db->selectCollection('billing_rates'); - $cursor = $table->find($mongo_where)->sort(array('reseller_id'=>-1))->limit(1)->slaveOkay(); - $result = $cursor->getNext(); - } catch (Exception $e) { - $log = sprintf("

Caught exception in lookupRateValuesAudio(): %s", $e->getMessage()); - syslog(LOG_NOTICE, $log); - return false; - } - - if (!$result) { - $log = sprintf("Error: cannot find mongo rate values for dest id %s", $DestinationId); - syslog(LOG_NOTICE, $log); - //return false; - } - - if ($result) { - $values=array( - "connectCost" => $result['connectCost'], - "durationRate" => $result['durationRate'], - "connectCostIn" => $result['connectCostIn'], - "durationRateIn" => $result['durationRateIn'] - ); - - // cache values - $this->rateValuesCache[$rateName][$DestinationId][$this->application]=$values; - return $values; - } - } - if ($this->settings['split_rating_table']) { if ($rateName) { $table="billing_rates_".$rateName; } else { $table="billing_rates_default"; } $query = sprintf( "select * from %s where destination = '%s' and application = '%s'", addslashes($table), addslashes($DestinationId), addslashes($this->application) ); } else { $table = "billing_rates"; $query = sprintf( "select * from %s where name = '%s' and destination = '%s' and application = '%s'", addslashes($table), addslashes($rateName), addslashes($DestinationId), addslashes($this->application) ); } // mysql backend if (!$this->db->query($query)) { if ($this->db->Errno != 1146) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return false; } // try the main table $query = sprintf( "select * from billing_rates where name = '%s' and destination = '%s' and application = '%s'", addslashes($rateName), addslashes($DestinationId), addslashes($this->application) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return false; } } if ($this->db->num_rows()) { $this->db->next_record(); $values = array( "connectCost" => $this->db->Record['connectCost'], "durationRate" => $this->db->Record['durationRate'], "connectCostIn" => $this->db->Record['connectCostIn'], "durationRateIn" => $this->db->Record['durationRateIn'] ); // cache values $this->rateValuesCache[$rateName][$DestinationId][$this->application] = $values; return $values; } else { return false; } } private function lookupRateValuesMessage($rateName, $DestinationId) { if (is_array($this->rateValuesCache[$rateName][$DestinationId]['sms'])) { return $this->rateValuesCache[$rateName][$DestinationId]['sms']; } - if ($this->mongo_db != null) { - // mongo backend - $mongo_where['application'] = 'sms'; - $mongo_where['$or'] = array( - array('reseller_id' => intval($this->ResellerId)), - array('reseller_id' => 0) - ); - $mongo_where['$or'] = array( - array('destination' => $DestinationId), - array('destination' => '') - ); - - try { - $table = $this->mongo_db->selectCollection('billing_rates'); - $cursor = $table->find($mongo_where)->sort(array('destination'=>-1))->limit(1)->slaveOkay(); - $result = $cursor->getNext(); - } catch (Exception $e) { - $log = sprintf("

Caught exception in lookupRateValuesMessage(): %s", $e->getMessage()); - syslog(LOG_NOTICE, $log); - return false; - } - - if (!$result) { - $log = sprintf( - "Error: cannot find mongo rate sms values for dest id %s", - $DestinationId - ); - syslog(LOG_NOTICE, $log); - //return false; - } - - if ($result) { - $values = array( - "connectCost" => $result['connectCost'] - ); - - // cache values - $this->rateValuesCache[$rateName][$DestinationId]['sms'] = $values; - return $values; - } - } - if ($this->settings['split_rating_table']) { if ($rateName) { $table = "billing_rates_".$rateName; } else { $table = "billing_rates_default"; } $query = sprintf( "select * from %s where (destination = '%s' or destination = '') and application = 'sms' order by destination desc limit 1", addslashes($table), addslashes($DestinationId) ); } else { $table = "billing_rates"; $query = sprintf( "select * from %s where name = '%s' and (destination = '%s' or destination = '') and application = 'sms' order by destination desc limit 1", addslashes($table), addslashes($rateName), addslashes($DestinationId) ); } // mysql backend if (!$this->db->query($query)) { if ($this->db->Errno != 1146) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return false; } // try the main table // lookup rate from MySQL $query = sprintf( "select * from billing_rates where name = '%s' and (destination = '%s' or destination = '') and application = 'sms' order by destination desc limit 1", addslashes($rateName), addslashes($DestinationId) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return false; } } if ($this->db->num_rows()) { $this->db->next_record(); $values = array( "connectCost" => $this->db->Record['connectCost'] ); // cache values $this->rateValuesCache[$rateName][$DestinationId]['sms']=$values; return $values; } else { return false; } } } class RatingTables { - var $database_backend = 'mysql'; // mongo or mysql + var $database_backend = 'mysql'; var $csv_export=array( "destinations" => "destinations.csv", "billing_customers" => "customers.csv", "billing_profiles" => "profiles.csv", "billing_rates" => "rates.csv", "billing_rates_history" => "ratesHistory.csv", "billing_discounts" => "discounts.csv", "billing_enum_tlds" => "enumtld.csv", "prepaid" => "prepaid.csv", "quota_usage" => "quotausage.csv" ); var $csv_import = array( "destinations" => "destinations.csv", "billing_customers" => "customers.csv", "billing_profiles" => "profiles.csv", "billing_rates" => "rates.csv", "billing_rates_history" => "ratesHistory.csv", "billing_discounts" => "discounts.csv" ); var $previously_imported_files = 0; var $maxrowsperpage = 15; var $insertDomainOption = array(); var $delimiter = ","; var $filesToImport = array(); var $importFilesPatterns = array( 'ratesHistory', 'rates', 'profiles', 'destinations', 'discounts', 'customers' ); var $mustReload = false; var $web_elements = array( 'table', 'export', 'web_task', 'subweb_task', 'confirmDelete', 'confirmCopy', 'next', 'id', 'search_text', 'ReloadRatingTables', 'account', 'balance', 'fromRate', 'toRate', 'sessionId' ); var $requireReload = array('destinations'); var $whereResellerFilter = " (1=1) "; var $cvs_import_dir = "/var/spool/cdrtool"; var $tables = array( "destinations" => array( "name" => "Destinations", "skip_math" => true, "keys" => array( "id" ), "exceptions" => array(), "order" => "dest_id ASC", "domainFilterColumn" => "domain", "fields" => array( "gateway" => array( "size" => 15, "checkType" => 'ip', "name" => "Trusted peer" ), "reseller_id" => array( "size" => 8, "checkType" => 'numeric', "name" => "Reseller" ), "domain" => array( "size" => 15, "name" => "Domain", "checkType" => 'domain', "class" => "span2" ), "subscriber" => array( "size" => 15, "checkType" => 'sip_account', "name" => "Subscriber", "class" => "span2" ), "dest_id" => array( "size" => 12, "name" => "Destination", ), "region" => array( "size" => 10, "name" => "Region" ), "dest_name" => array( "size" => 20, "name" => "Description", "class" => "span2" ), "increment" => array( "size" => 3, "checkType" => 'numeric', "name" => "Incr" ), "min_duration" => array( "size" => 3, "checkType" => 'numeric', "name" => "Min Dur" ), "max_duration" => array( "size" => 5, "checkType" => 'numeric', "name" => "Max Dur" ), "max_price" => array( "size" => 8, "checkType" => 'numeric', "name" => "Max Price" ) ) ), "billing_customers" => array( "name" => "Customers", "skip_math" => true, "keys" => array("id"), "domainFilterColumn" => "domain", "fields" => array( "gateway" => array( "size" => 15, "checkType" => 'ip', "name" => "Trusted Peer" ), "reseller_id" => array( "size" => 8, "checkType" => 'numeric', "name" => "Reseller" ), "domain" => array( "size" => 15, "checkType" => 'domain', "name" => "Domain", "class" => "span2" ), "subscriber" => array( "size" => 25, "checkType" => 'sip_account', "name" => "Subscriber", "class" => "span2" ), "profile_name1" => array( "size" => 10, "name" => "Profile WD" ), "profile_name1_alt" => array( "size" => 8, "name" => "Fallback" ), "profile_name2" => array( "size" => 10, "name" => "Profile WE" ), "profile_name2_alt" => array( "size" => 8, "name" => "Fallback" ), "timezone" => array( "size" => 16, "name" => "Timezone", "class" => "span2" ), "increment" => array( "size" => 3, "checkType" => 'numeric', "name" => "Incr" ), "min_duration" => array( "size" => 3, "checkType" => 'numeric', "name" => "Min Dur" ) ) ), "billing_discounts" => array( "name" => "Discounts", "keys" => array("id"), "domainFilterColumn" => "domain", "fields" => array( "gateway" => array( "size" => 15, "checkType" => 'ip', "name" => "Trusted Peer" ), "reseller_id" => array( "size" => 8, "checkType" => 'numeric', "name" => "Reseller" ), "domain" => array( "size" => 15, "checkType" => 'domain', "name" => "Domain", "class" => "span2" ), "subscriber" => array( "size" => 25, "checkType" => 'sip_account', "name" => "Subscriber", "class" => "span2" ), "application" => array( "size" => 6, "name" => "App" ), "destination" => array( "size" => 10, "name" => "Destination" ), "region" => array( "size" => 8, "name" => "Region" ), "connect" => array( "size" => 5, "name" => "Connect" ), "duration" => array( "size" => 5, "name" => "Duration" ) ) ), "billing_profiles" => array( "name" => "Profiles", "skip_math" => true, "keys" => array("id"), "exceptions" => array(), "size" => 6, "fields" => array( "reseller_id" => array( "size" => 8, "checkType" => 'numeric', "name" => "Reseller" ), "name" => array( "size" => 12, "name" => "Profile", "class" => "span2" ), "rate_name1" => array( "size" => 12, "name" => "Rate 1" ), "hour1" => array( "size" => 3, "checkType" => 'numeric', "name" => "00-H1" ), "rate_name2" => array( "size" => 12, "name" => "Rate 2" ), "hour2" => array( "size" => 3, "checkType" => 'numeric', "name" => "H1-H2" ), "rate_name3" => array( "size" => 12, "name" => "Rate 3" ), "hour3" => array( "size" => 3, "checkType" => 'numeric', "name" => "H2-H3" ), "rate_name4" => array( "size" => 12, "name" => "Rate 4" ), "hour4" => array( "size" => 3, "checkType" => 'numeric', "name" => "H3-24" ), ) ), "billing_rates" => array( "name" => "Rates", "keys" => array("id"), "size" => 10, "exceptions" => array('maxPrice'), "order" => "durationRate desc", "fields" => array( "reseller_id" => array( "size" => 8, "checkType" => 'numeric', "name" => "Reseller" ), "name" => array( "size" => 12, "name" => "Rate", "class" => "span2" ), "destination" => array( "size" => 12, "name" => "Destination" ), "application" => array( "size" => 6, "name" => "App" ), "connectCost" => array( "size" => 8, "checkType" => 'numeric', "name"=>"Connect" ), "durationRate" => array( "size" => 8, "checkType" => 'numeric', "name" => "Duration" ), "connectCostIn" => array( "size" => 8, "checkType" => 'numeric', "name" => "Conn In" ), "durationRateIn" => array( "size" => 8, "checkType" => 'numeric', "name" => "Duration In" ) ) ), "billing_rates_history" => array( "name" => "Rates history", "keys" => array("id"), "size" => 10, "order" => "destination ASC, name ASC", "fields" => array( "reseller_id" => array( "size" => 8, "checkType" => 'numeric', "name" => "Reseller" ), "name" => array( "size" => 10, "name" => "Rate", "class" => "span2" ), "destination" => array( "size" => 12, "name" => "Destination" ), "application" => array( "size" => 6, "name" => "App" ), "connectCost" => array( "size" => 8, "checkType" => 'numeric', "name" => "Conn" ), "durationRate" => array( "size" => 8, "checkType" => 'numeric', "name" => "Price" ), "connectCostIn" => array( "size" => 8, "checkType" => 'numeric', "name" => "Conn In" ), "durationRateIn" => array( "size" => 8, "checkType" => 'numeric', "name" => "Price In" ), "startDate" => array( "size" => 11, "name" => "Start Date", "class" => "span2" ), "endDate" => array( "size" => 11, "name" => "End Date", "class" => "span2" ) ) ), "billing_enum_tlds" => array( "name" => "ENUM discounts", "skip_math" => true, "keys" => array("id"), "exceptions" => array(), "size" => 6, "fields" => array( "reseller_id" => array( "size" => 8, "checkType" => 'numeric', "name" => "Reseller" ), "enum_tld" => array( "size" => 35, "mustExist" => true, "checkType" => 'domain', "name" => "ENUM TLD", "class" => "span2" ), "e164_regexp" => array( "size" => 35, "mustExist" => true, "name" => "E164 Regexp", "class" => "span2" ), "discount" => array( "size" => 10, "mustExist" => true, "checkType" => 'numeric', "name" => "Discount" ) ) ), "prepaid" => array( "name" => "Prepaid accounts", "keys" => array("id"), "size" => 15, "exceptions" => array('change_date','active_sessions','domain'), "order" => "change_date DESC", "fields" => array( "account" => array( "size" => 35, "name" => "Subscriber", "checkType" => 'sip_account', "mustExist" => true, "class" => "span2" ), "reseller_id" => array( "size" => 8, "checkType" => 'numeric', "name" => "Reseller" ), "balance" => array( "size" => 10, "name" => "Balance" ), "change_date" => array( "size" => 19, "name" => "Last Change", "readonly" => 1 ), "session_counter" => array( "size" => 3, "name" => "Active Sessions", "readonly" => 1 ), "max_sessions" => array( "size" => 3, "name" => "Max Sessions" ) ) ), "prepaid_cards" => array( "name" => "Prepaid cards", "keys" => array("id"), "size" => 15, "exceptions" => array('service'), "fields" => array( "batch" => array( "size" => 40, "name" => "Batch name", "readonly" => 1, "class" => "span3" ), "reseller_id" => array( "size" => 8, "checkType" => 'numeric', "name" => "Reseller" ), "date_batch" => array( "size" => 11, "name" => "Batch Date", "class" => "span2" ), "number" => array( "size" => 20, "checkType" => 'numeric', "mustExist" => true, "name" => "Card Number", "class" => "span2" ), "id" => array( "size" => 20, "checkType" => 'numeric', "mustExist" => true, "name" => "Card Id", ), "value" => array( "size" => 8, "checkType" => 'numeric', "mustExist" => true, "name" => "Card Value" ), "blocked" => array( "size" => 1, "name" => "Lock" ), "date_active" => array( "size" => 18, "name" => "Activation Date", "class" => "span2" ) ) ), "prepaid_history" => array( "name" => "Prepaid history", "order" => "id DESC", "skip_math" => true, "keys" => array("id"), "size" => 15, "exceptions" => array('session','destination'), "fields" => array( "username" => array( "size" => 15, "readonly" => 1, "class" => "span2" ), "domain" => array( "size" => 15, "readonly" => 1, "class" => "span2" ), "reseller_id" => array( "size" => 8, "checkType" => 'numeric', "name" => "Reseller", "readonly" => 1 ), "action" => array( "size" => 15, "readonly" => 1, "class" => "span2" ), "duration" => array( "size" => 5 ), "destination" => array( "size" => 15 ), "session" => array( "size" => 30, "readonly" => 1 ), "description" => array( "size" => 30, "class" => "span3" ), "value" => array( "size" => 10 ), "balance" => array( "size" => 10 ), "date" => array( "size" => 18, "class" => "span2" ) ) ), "quota_usage" => array( "name" => "Quota usage", "keys" => array("id"), "size" => 15, "readonly" => 1, "exceptions" => array( "change_date", "traffic", "duration", "calls" ), "domainFilterColumn" => "domain", "fields" => array( "datasource" => array( "size" => 15, "readonly" => 1 ), "reseller_id" => array( "size" => 8, "checkType" => 'numeric', "name" => "Reseller", "readonly" => true ), "account" => array( "size" => 30, "readonly" => 1, "name" => "Subscriber", "class" => "span2" ), "domain" => array( "size" => 15, "readonly" => 1, "class" => "span2" ), "blocked" => array( "size" => 2, "readonly" => 1 ), "notified" => array( "size" => 20, "readonly" => 1 ), "quota" => array( "size" => 5, "readonly" => 1 ), "cost" => array( "size" => 10, "readonly" => 1, "name" => "This Month" ), "cost_today" => array( "size" => 10, "readonly" => 1, "name" => "Today" ), "duration" => array( "size" => 10, "readonly" => 1 ), "calls" => array( "size" => 10, "readonly" => 1 ), "traffic" => array( "size" => 20, "readonly" => 1 ) ) ) ); public function RatingTables($readonly = false) { global $CDRTool; global $RatingEngine; - $this->mongo_db_ro = null; - $this->mongo_db_rw = null; - $this->settings = $RatingEngine; $this->CDRTool = $CDRTool; $this->table = $_REQUEST['table']; if (!$this->table || !in_array($this->table, array_keys($this->tables))) { $this->table="destinations"; } $this->readonly=$readonly; if ($this->settings['csv_delimiter']) { $this->delimiter=$this->settings['csv_delimiter']; } if (!strlen($this->CDRTool['filter']['customer'])) { $this->whereResellerFilter = sprintf("reseller_id = %d", '99999999'); } else { if ($this->CDRTool['filter']['customer'] && $this->tables[$this->table]['fields']['reseller_id']) { $this->whereResellerFilter = sprintf("reseller_id = %d", addslashes($this->CDRTool['filter']['customer'])); $this->tables[$this->table]['fields']['reseller_id']['readonly']=true; } } if ($this->settings['split_rating_table']) { $this->tables['billing_rates']['fields']['name']['readonly'] = 1; } if (strlen($this->settings['socketIP'])) { if ($this->settings['socketIP'] == '0.0.0.0' || $this->settings['socketIP'] == '0') { $this->settings['socketIPforClients'] = '127.0.0.1'; } else { $this->settings['socketIPforClients'] = $this->settings['socketIP']; } } if ($this->settings['database_backend']) { $this->database_backend = $this->settings['database_backend']; } $this->db = new DB_cdrtool; $this->db1 = new DB_cdrtool; $this->db->Halt_On_Error="no"; $this->db1->Halt_On_Error="no"; - if ($this->database_backend == "mysql") { - # TODO - } elseif ($this->database_backend == "mongo") { - $this->mongo_safe = 1; - if (is_array($this->settings['mongo_db'])) { - $mongo_uri = $this->settings['mongo_db']['uri']; - $mongo_replicaSet = $this->settings['mongo_db']['replicaSet']; - $mongo_database = $this->settings['mongo_db']['database']; - if ($this->settings['mongo_db']['safe']) { - $this->mongo_safe = $this->settings['mongo_db']['safe']; - } - try { - $mongo_connection_rw = new Mongo( - "mongodb://$mongo_uri?readPreference=primaryPreferred", - array( - "replicaSet" => $mongo_replicaSet - ) - ); - $mongo_connection_ro = new Mongo( - "mongodb://$mongo_uri?readPreference=secondaryPreferred", - array( - "replicaSet" => $mongo_replicaSet - ) - ); - $this->mongo_db_rw = $mongo_connection_rw->selectDB($mongo_database); - $this->mongo_db_ro = $mongo_connection_ro->selectDB($mongo_database); - } catch (Exception $e) { - $log = sprintf("Error: mongo exception in RatingTables(): %s", $e->getMessage()); - syslog(LOG_NOTICE, $log); - } - - $existing_rating_tables=array(); - try { - $_tables=$this->mongo_db_ro->listCollections(); - foreach ($_tables as $_table) { - list($collection, $table) = explode(".", strval($_table)); - $existing_rating_tables[]=$table; - } - } catch (Exception $e) { - $log = sprintf("

Caught exception in RatingTables(): %s", $e->getMessage()); - syslog(LOG_NOTICE, $log); - } - - foreach (array_keys($this->csv_export) as $table) { - if (!in_array($table, $existing_rating_tables)) { - try { - $this->mongo_db_rw->command(array("create" => $table)); - $log=sprintf("Created mongo collection %s", $table); - syslog(LOG_NOTICE, $log); - } catch (Exception $e) { - $log=sprintf("Error creating mongo collection %s: %s", $table, $e->getMessage()); - syslog(LOG_NOTICE, $log); - } - } - } - } - } } public function ImportCSVFiles($dir = false) { $results = 0; if (!$dir) $dir = "/var/spool/cdrtool"; $this->scanFilesForImport($dir); if ($this->previously_imported_files) { printf("Skipping %d previously imported files\n", $this->previously_imported_files); } $results=0; foreach (array_keys($this->filesToImport) as $file) { $importFunction = "Import".ucfirst($this->filesToImport[$file]['type']); printf("Reading file %s\n", $this->filesToImport[$file]['path']); $results = $this->$importFunction($this->filesToImport[$file]['path'],$this->filesToImport[$file]['reseller']); $this->logImport( $dir, $this->filesToImport[$file]['path'], $this->filesToImport[$file]['watermark'], $results, $this->filesToImport[$file]['reseller'] ); } return $results; } private function ImportRates($file, $reseller = 0) { if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false; $i=0; $inserted = 0; $updated = 0; $deleted = 0; printf("Importing rates from %s for reseller %s:\n", $file, $reseller); while ($buffer = fgets($fp, 1024)) { $buffer = trim($buffer); $p = explode($this->delimiter, $buffer); $ops = trim($p[0]); $name = trim($p[2]); $destination = trim($p[3]); $application = trim($p[4]); $connectCost = trim($p[5]); $durationRate = trim($p[6]); $connectCostIn = trim($p[7]); $durationRateIn = trim($p[8]); if ($reseller) { $reseller_id = intval($reseller); } else { $reseller_id = intval($p[1]); } if (!is_numeric($destination) && !strstr($destination, '@')) { // skip invalid destinations $skipped++; continue; } if (strlen($connectCost) && !is_numeric($connectCost)) { $skipped++; continue; } if (strlen($durationRate) && !is_numeric($durationRate)) { $skipped++; continue; } if (!$application) $application='audio'; if ($ops=="1") { $query = sprintf( "insert into billing_rates ( reseller_id, name, destination, application, connectCost, durationRate, connectCostIn, durationRateIn ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($name), addslashes($destination), addslashes($application), addslashes($connectCost), addslashes($durationRate), addslashes($connectCostIn), addslashes($durationRateIn) ); // mysql backend if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); } if ($this->db->affected_rows()) { if ($this->settings['split_rating_table']) { if ($name) { $_table = 'billing_rates_'.$name; } else { $_table = 'billing_rates_default'; } if (!$this->createRatingTable($name)) { $query = sprintf( "insert into %s ( id, reseller_id, name, destination, application, connectCost, durationRate, connectCostIn, durationRateIn ) values ( LAST_INSERT_ID(), '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($_table), addslashes($reseller_id), addslashes($name), addslashes($destination), addslashes($application), addslashes($connectCost), addslashes($durationRate), addslashes($connectCostIn), addslashes($durationRateIn) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } } } $inserted++; } else { $failed++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'name' => $name, - 'destination' => $destination, - 'application' => $application, - 'connectCost' => intval($connectCost), - 'durationRate' => intval($durationRate), - 'connectCostIn' => intval($connectCostIn), - 'durationRateIn' => intval($durationRateIn) - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when inserting in billing_rates: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } elseif ($ops == "3") { $query = sprintf( "delete from billing_rates where reseller_id = '%s' and name = '%s' and destination = '%s' and application = '%s'", addslashes($reseller_id), addslashes($name), addslashes($destination), addslashes($application) ); // mysql backend if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows()) { if ($this->settings['split_rating_table']) { if ($name) { $_table = 'billing_rates_'.$name; } else { $_table = 'billing_rates_default'; } $query = sprintf( "delete from %s where reseller_id = '%s' and name = '%s' and destination = '%s' and application = '%s'", addslashes($_table), addslashes($reseller_id), addslashes($name), addslashes($destination), addslashes($application) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); } } $deleted++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates'); - $mongo_match = array( - 'reseller_id' => intval(reseller_id), - 'name' => $name, - 'destination' => $destination, - 'application' => $application - ); - $mongo_table_rw->remove( - $mongo_match, - array( - "safe" => $self->mongo_safe - ) - ); - } catch (Exception $e) { - $log = sprintf("Error: Mongo exception when deleting from billing_rates: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } - } elseif ($ops == "2") { - $query = sprintf( - "select * from billing_rates - where name = '%s' - and destination = '%s' - and reseller_id = '%s' - and application = '%s' - ", - addslashes($name), - addslashes($destination), - addslashes($reseller_id), - addslashes($application) - ); - // mysql backend if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->num_rows()) { $query = sprintf( "update billing_rates set connectCost = '%s', durationRate = '%s', connectCostIn = '%s', durationRateIn = '%s' where name = '%s' and destination = '%s' and reseller_id = '%s' and application = '%s' ", addslashes($connectCost), addslashes($durationRate), addslashes($connectCostIn), addslashes($durationRateIn), addslashes($name), addslashes($destination), addslashes($reseller_id), addslashes($application) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows()) { if ($this->settings['split_rating_table']) { if ($name) { $_table = 'billing_rates_'.$name; } else { $_table = 'billing_rates_default'; } $query = sprintf( "update %s set connectCost = '%s', durationRate = '%s', connectCostIn = '%s', durationRateIn = '%s' where name = '%s' and destination = '%s' and reseller_id = '%s' and application = '%s' ", addslashes($_table), addslashes($connectCost), addslashes($durationRate), addslashes($connectCostIn), addslashes($durationRateIn), addslashes($name), addslashes($destination), addslashes($reseller_id), addslashes($application) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); } } $updated++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_match = array( - 'reseller_id' => intval(reseller_id), - 'name' => $name, - 'destination' => $destination, - 'application' => $application - ); - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'name' => $name, - 'destination' => $destination, - 'application' => $application, - 'connectCost' => intval($connectCost), - 'durationRate' => intval($durationRate), - 'connectCostIn' => intval($connectCostIn), - 'durationRateIn' => intval($durationRateIn) - ); - $mongo_options = array( - "upsert" => true, - "safe" => $self->mongo_safe - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates'); - $result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when updating billing_rates: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } else { $query = sprintf( "insert into billing_rates ( reseller_id, name, destination, application, connectCost, durationRate, connectCostIn, durationRateIn ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($name), addslashes($destination), addslashes($application), addslashes($connectCost), addslashes($durationRate), addslashes($connectCostIn), addslashes($durationRateIn) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows()) { if ($this->settings['split_rating_table']) { if ($name) { $_table = 'billing_rates_'.$name; } else { $_table = 'billing_rates_default'; } if (!$this->createRatingTable($name)) { $query = sprintf( "insert into %s ( id, reseller_id, name, destination, application connectCost, durationRate, connectCostIn, durationRateIn ) values ( LAST_INSERT_ID(), '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($_table), addslashes($reseller_id), addslashes($name), addslashes($destination), addslashes($application), addslashes($connectCost), addslashes($durationRate), addslashes($connectCostIn), addslashes($durationRateIn) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } } } $inserted++; } else { $failed++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'name' => $name, - 'destination' => $destination, - 'application' => $application, - 'connectCost' => intval($connectCost), - 'durationRate' => intval($durationRate), - 'connectCostIn' => intval($connectCostIn), - 'durationRateIn' => intval($durationRateIn) - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log = sprintf("Error: Mongo exception when inserting in billing_rates: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - } - } - } } } else { $skipped++; } $this->showImportProgress($file); $i++; } if ($i) print "Read $i records\n"; if ($skipped) print "Skipped $skipped records\n"; if ($inserted) print "Inserted $inserted records\n"; if ($updated) print "Updated $updated records\n"; if ($deleted) print "Delete $deleted records\n"; $results = $inserted+$updated+$deleted; return $results; } private function ImportRatesHistory($file, $reseller = 0) { if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false; $this->mustReload=true; $i=0; $inserted = 0; $updated = 0; $deleted = 0; printf("Importing rates history from %s for reseller %s:\n", $file, $reseller); while ($buffer = fgets($fp, 1024)) { $buffer=trim($buffer); $p = explode($this->delimiter, $buffer); $ops = trim($p[0]); $name = trim($p[2]); $destination = trim($p[3]); $application = trim($p[4]); $connectCost = trim($p[5]); $durationRate = trim($p[6]); $connectCostIn = trim($p[7]); $durationRateIn = trim($p[8]); $startDate = trim($p[9]); $endDate = trim($p[10]); if ($reseller) { $reseller_id = intval($reseller); } else { $reseller_id = intval($p[1]); } if (!is_numeric($destination) && !strstr($destination, '@')) { // skip invalid destinations $skipped++; continue; } if (strlen($connectCost) && !is_numeric($connectCost)) { $skipped++; continue; } if (strlen($durationRate) && !is_numeric($durationRate)) { $skipped++; continue; } if (preg_match("/^\d{4}\-{\d{2}\-\d{2}$/", $startDate)) { $skipped++; continue; } if (preg_match("/^\d{4}\-{\d{2}\-\d{2}$/", $endDate)) { $skipped++; continue; } if ($ops=="1") { $query = sprintf( "insert into billing_rates_history ( reseller_id, name, destination, application, connectCost, durationRate, connectCostIn, durationRateIn, startDate, endDate ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($name), addslashes($destination), addslashes($application), addslashes($connectCost), addslashes($durationRate), addslashes($connectCostIn), addslashes($durationRateIn), addslashes($startDate), addslashes($endDate) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $inserted++; } else { $failed++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'name' => $name, - 'destination' => $destination, - 'application' => $application, - 'connectCost' => intval($connectCost), - 'durationRate' => intval($durationRate), - 'connectCostIn' => intval($connectCostIn), - 'durationRateIn' => intval($durationRateIn), - 'startDate' => $startDate, - 'endDate' => $endDate - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates_history'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when inserting in billing_rates_history: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - } - } - } } elseif ($ops=="3") { $query = sprintf( "delete from billing_rates_history where reseller_id = '%s' and name = '%s' and destination = '%s' and startDate = '%s' and endDate = '%s'", addslashes($reseller_id), addslashes($name), addslashes($destination), addslashes($startDate), addslashes($endDate) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $deleted++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates_history'); - $mongo_match = array( - 'reseller_id' => intval(reseller_id), - 'name' => $name, - 'destination' => $destination, - 'application' => $application, - 'startDate' => $startDate, - 'endDate' => $endDate - ); - $mongo_table_rw->remove( - $mongo_match, - array("safe" => $self->mongo_safe) - ); - } catch (Exception $e) { - $log = sprintf("Error: Mongo exception when deleting from billing_rates_history: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } elseif ($ops=="2") { $query = sprintf( "select * from billing_rates_history where name = '%s' and destination = '%s' and reseller_id = '%s' and startDate = '%s' and endDate = '%s' ", addslashes($name), addslashes($destination), addslashes($reseller_id), addslashes($startDate), addslashes($endDate) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->num_rows()) { $query = sprintf( "update billing_rates_history set application = '%s', connectCost = '%s', durationRate = '%s', connectCostIn = '%s', connectCostIn = '%s' where name = '%s' and destination = '%s' and reseller_id = '%s' and startDate = '%s' and endDate = '%s' ", addslashes($application), addslashes($connectCost), addslashes($durationRate), addslashes($connectCostIn), addslashes($durationRateIn), addslashes($name), addslashes($destination), addslashes($reseller_id), addslashes($startDate), addslashes($endDate) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $updated++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_match = array( - 'reseller_id' => intval(reseller_id), - 'name' => $name, - 'destination' => $destination, - 'application' => $application, - 'startDate' => $startDate, - 'endDate' => $endDate - ); - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'name' => $name, - 'destination' => $destination, - 'application' => $application, - 'connectCost' => intval($connectCost), - 'durationRate' => intval($durationRate), - 'connectCostIn' => intval($connectCostIn), - 'durationRateIn' => intval($durationRateIn), - 'startDate' => $startDate, - 'endDate' => $endDate - ); - $mongo_options = array( - "upsert" => true, - "safe" => $self->mongo_safe - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates_history'); - $result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when updating billing_rates_history: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } else { $query = sprintf( "insert into billing_rates_history ( reseller_id, name, destination, application, connectCost, durationRate, connectCostIn, durationRateIn, startDate, endDate ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($name), addslashes($destination), addslashes($application), addslashes($connectCost), addslashes($durationRate), addslashes($connectCostIn), addslashes($durationRateIn), addslashes($startDate), addslashes($endDate) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $inserted++; } else { $failed++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_data=array( - 'reseller_id' => intval(reseller_id), - 'name' => $name, - 'destination' => $destination, - 'application' => $application, - 'connectCost' => intval($connectCost), - 'durationRate' => intval($durationRate), - 'connectCostIn' => intval($connectCostIn), - 'durationRateIn' => intval($durationRateIn), - 'startDate' => $startDate, - 'endDate' => $endDate - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_rates_history'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log = sprintf("Error: Mongo exception when inserting in billing_rates_history: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - } - } - } } } else { $skipped++; } $j++; if ($j=="10000") { flush(); $j=0; } $this->showImportProgress($file); $i++; } if ($i) print "Read $i records\n"; if ($skipped) print "Skipped $skipped records\n"; if ($inserted) print "Inserted $inserted records\n"; if ($updated) print "Updated $updated records\n"; if ($deleted) print "Delete $deleted records\n"; $results = $inserted + $updated + $deleted; return $results; } private function ImportCustomers($file, $reseller = 0) { if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false; $this->mustReload = true; $i=0; $inserted = 0; $updated = 0; $deleted = 0; printf("Importing customers from %s for reseller %s:\n", $file, $reseller); while ($buffer = fgets($fp, 1024)) { $buffer=trim($buffer); $p = explode($this->delimiter, $buffer); $ops = trim($p[0]); $gateway = trim($p[2]); $domain = trim($p[3]); $subscriber = trim($p[4]); $profile_name1 = trim($p[5]); $profile_name1_alt = trim($p[6]); $profile_name2 = trim($p[7]); $profile_name2_alt = trim($p[8]); $timezone = trim($p[9]); if ($reseller) { $reseller_id = intval($reseller); } else { $reseller_id = intval($p[1]); } if (strlen($reseller_id) && !is_integer($reseller_id)) { $skipped++; continue; } if ($ops=="1") { $query = sprintf( "insert into billing_customers ( reseller_id, gateway, domain, subscriber, profile_name1, profile_name2, timezone, profile_name1_alt, profile_name2_alt ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($gateway), addslashes($domain), addslashes($subscriber), addslashes($profile_name1), addslashes($profile_name2), addslashes($timezone), addslashes($profile_name1_alt), addslashes($profile_name2_alt) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $inserted++; } else { $failed++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'gateway' => $gateway, - 'domain' => $domain, - 'subscriber' => $subscriber, - 'profile_name1' => $profile_name1, - 'profile_name2' => $profile_name2, - 'profile_name1_alt' => $profile_name1_alt, - 'profile_name2_alt' => $profile_name2_alt, - 'timezone' => $timezone - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_customers'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log = sprintf("Error: Mongo exception when inserting in billing_customers: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } elseif ($ops == "3") { $query = sprintf( "delete from billing_customers where gateway = '%s' and reseller_id = '%s' and domain = '%s' and subscriber = '%s' ", addslashes($gateway), addslashes($reseller_id), addslashes($domain), addslashes($subscriber) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $deleted++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_customers'); - $mongo_match = array( - 'gateway' => $gateway, - 'reseller_id' => intval(reseller_id), - 'domain' => $domain, - 'subscriber' => $subscriber, - 'dest_id' => $dest_id - ); - $mongo_table_rw->remove( - $mongo_match, - array("safe" => $self->mongo_safe) - ); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when deleting from billing_customers: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } elseif ($ops == "2") { $query = sprintf( "select * from billing_customers where gateway = '%s' and reseller_id = '%s' and domain = '%s' and subscriber = '%s' ", addslashes($gateway), addslashes($reseller_id), addslashes($domain), addslashes($subscriber) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->num_rows()) { $query = sprintf( "update billing_customers set profile_name1 = '%s', profile_name2 = '%s', profile_name1_alt = '%s', profile_name2_alt = '%s', timezone = '%s' where gateway = '%s' and domain = '%s' and reseller_id = '%s' and subscriber = '%s'\n", addslashes($profile_name1), addslashes($profile_name2), addslashes($profile_name1_alt), addslashes($profile_name2_alt), addslashes($timezone), addslashes($gateway), addslashes($domain), addslashes($reseller_id), addslashes($subscriber) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows()) { $updated++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_match = array( - 'gateway' => $gateway, - 'reseller_id' => intval(reseller_id), - 'domain' => $domain, - 'subscriber' => $subscriber - ); - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'gateway' => $gateway, - 'domain' => $domain, - 'subscriber' => $subscriber, - 'profile_name1' => $profile_name1, - 'profile_name2' => $profile_name2, - 'profile_name1_alt' => $profile_name1_alt, - 'profile_name2_alt' => $profile_name2_alt, - 'timezone' => $timezone - ); - $mongo_options = array("upsert" => true, - "safe" => $self->mongo_safe - ); - - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_customers'); - $result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when updating billing_customers: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } else { $query = sprintf( "insert into billing_customers ( reseller_id, gateway, domain, subscriber, profile_name1, profile_name2, timezone, profile_name1_alt, profile_name2_alt ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($gateway), addslashes($domain), addslashes($subscriber), addslashes($profile_name1), addslashes($profile_name2), addslashes($timezone), addslashes($profile_name1_alt), addslashes($profile_name2_alt) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows()) { $inserted++; } - if ($this->mongo_db_rw) { - $mongo_data=array('reseller_id' => intval(reseller_id), - 'gateway' => $gateway, - 'domain' => $domain, - 'subscriber' => $subscriber, - 'profile_name1' => $profile_name1, - 'profile_name2' => $profile_name2, - 'profile_name1_alt' => $profile_name1_alt, - 'profile_name2_alt' => $profile_name2_alt, - 'timezone' => $timezone - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_customers'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when inserting in billing_customers: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } } } else { $skipped++; } $this->showImportProgress($file); $i++; } if ($i) print "Read $i records\n"; if ($skipped) print "Skipped $skipped records\n"; if ($inserted) print "Inserted $inserted records\n"; if ($updated) print "Updated $updated records\n"; if ($deleted) print "Delete $deleted records\n"; $results=$inserted+$updated+$deleted; return $results; } private function ImportDestinations($file, $reseller = 0) { if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false; $this->mustReload=true; $i=0; $inserted = 0; $updated = 0; $deleted = 0; printf("Importing destinations from %s for reseller %s:\n", $file, $reseller); while ($buffer = fgets($fp, 1024)) { $buffer=trim($buffer); $p = explode($this->delimiter, $buffer); $ops = trim($p[0]); $gateway = trim($p[2]); $domain = trim($p[3]); $subscriber = trim($p[4]); $dest_id = trim($p[5]); $region = trim($p[6]); $dest_name = trim($p[7]); $increment = intval($p[8]); $min_duration = intval($p[9]); $max_duration = intval($p[10]); $max_price = trim($p[11]); if ($reseller) { $reseller_id = intval($reseller); } else { $reseller_id = intval($p[1]); } if (!is_numeric($dest_id) && !strstr($dest_id, '@')) { // skip invalid destinations $skipped++; continue; } if ($ops=="1") { $query = sprintf( "insert into destinations ( reseller_id, gateway, domain, subscriber, dest_id, region, dest_name, increment, min_duration, max_duration, max_price ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($gateway), addslashes($domain), addslashes($subscriber), addslashes($dest_id), addslashes($region), addslashes($dest_name), addslashes($increment), addslashes($min_duration), addslashes($max_duration), addslashes($max_price) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $inserted++; } else { $failed++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'gateway' => $gateway, - 'domain' => $domain, - 'subscriber' => $subscriber, - 'dest_id' => $dest_id, - 'region' => $region, - 'dest_name' => $dest_name, - 'increment' => intval($increment), - 'min_duration' => intval($min_duration), - 'max_duration' => intval($max_duration), - 'max_price' => floatval($max_price) - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('destinations'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when inserting in destinations: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } elseif ($ops == "3") { $query = sprintf( "delete from destinations where gateway = '%s' and reseller_id = '%s' and domain = '%s' and subscriber = '%s' and dest_id = '%s' ", addslashes($gateway), addslashes($reseller_id), addslashes($domain), addslashes($subscriber), addslashes($dest_id) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $deleted++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('destinations'); - $mongo_match = array( - 'gateway' => $gateway, - 'reseller_id' => intval(reseller_id), - 'domain' => $domain, - 'subscriber' => $subscriber, - 'dest_id' => $dest_id - ); - $mongo_table_rw->remove( - $mongo_match, - array("safe" => $self->mongo_safe) - ); - } catch (Exception $e) { - $log = sprintf("Error: Mongo exception when deleting from destinations: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } elseif ($ops == "2") { $query = sprintf( "select * from destinations where gateway = '%s' and reseller_id = '%s' and domain = '%s' and subscriber = '%s' and dest_id = '%s' ", addslashes($gateway), addslashes($reseller_id), addslashes($domain), addslashes($subscriber), addslashes($dest_id) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->num_rows()) { $query = sprintf( "update destinations set region = '%s', dest_name = '%s', increment = '%s', min_duration = '%s', max_duration = '%s', max_price = '%s' where gateway = '%s' and reseller_id = '%s' and domain = '%s' and subscriber = '%s' and dest_id = '%s' ", addslashes($region), addslashes($dest_name), addslashes($increment), addslashes($min_duration), addslashes($max_duration), addslashes($max_price), addslashes($gateway), addslashes($reseller_id), addslashes($domain), addslashes($subscriber), addslashes($dest_id) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows()) { $updated++; } - dprint($this->database_backend); - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_match = array( - 'gateway' => $gateway, - 'reseller_id' => intval(reseller_id), - 'domain' => $domain, - 'subscriber' => $subscriber, - 'dest_id' => $dest_id - ); - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'gateway' => $gateway, - 'domain' => $domain, - 'subscriber' => $subscriber, - 'dest_id' => $dest_id, - 'region' => $region, - 'dest_name' => $dest_name, - 'increment' => intval($increment), - 'min_duration' => intval($min_duration), - 'max_duration' => intval($max_duration), - 'max_price' => floatval($max_price) - ); - $mongo_options = array( - "upsert" => true, - "safe" => $self->mongo_safe - ); - - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('destinations'); - $result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options); - } catch (Exception $e) { - $log = sprintf("Error: Mongo exception when updating destinations: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } else { $query = sprintf( "insert into destinations ( reseller_id, gateway, domain, subscriber, dest_id, region, dest_name, increment, min_duration, max_duration, max_price ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($gateway), addslashes($domain), addslashes($subscriber), addslashes($dest_id), addslashes($region), addslashes($dest_name), addslashes($increment), addslashes($min_duration), addslashes($max_duration), addslashes($max_price) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $inserted++; } else { $failed++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'gateway' => $gateway, - 'domain' => $domain, - 'subscriber' => $subscriber, - 'dest_id' => $dest_id, - 'region' => $region, - 'dest_name' => $dest_name, - 'increment' => intval($increment), - 'min_duration' => intval($min_duration), - 'max_duration' => intval($max_duration), - 'max_price' => floatval($max_price) - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('destinations'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when inserting in destinations: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - } - } - } } } else { $skipped++; } $this->showImportProgress($file); $i++; } if ($i) print "Read $i records\n"; if ($skipped) print "Skipped $skipped records\n"; if ($inserted) print "Inserted $inserted records\n"; if ($updated) print "Updated $updated records\n"; if ($deleted) print "Delete $deleted records\n"; $results = $inserted + $updated + $deleted; return $results; } private function ImportDiscounts($file, $reseller = 0) { if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false; $this->mustReload=true; $i=0; $inserted = 0; $updated = 0; $deleted = 0; printf("Importing discounts from %s for reseller %s:\n", $file, $reseller); while ($buffer = fgets($fp, 1024)) { $buffer=trim($buffer); $p = explode($this->delimiter, $buffer); $ops = trim($p[0]); $gateway = trim($p[2]); $domain = trim($p[3]); $subscriber = trim($p[4]); $application = trim($p[5]); $destination = trim($p[6]); $region = trim($p[7]); $connect = intval($p[8]); $duration = intval($p[9]); if ($reseller) { $reseller_id = intval($reseller); } else { $reseller_id = intval($p[1]); } if (!is_numeric($destination) && !strstr($destination, '@')) { // skip invalid destinations $skipped++; continue; } if ($ops == "1") { $query = sprintf( "insert into billing_discounts ( reseller_id, gateway, domain, subscriber, application, destination, region, connect, duration ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($gateway), addslashes($domain), addslashes($subscriber), addslashes($application), addslashes($destination), addslashes($region), addslashes($connect), addslashes($duration) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $inserted++; } else { $failed++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'gateway' => $gateway, - 'domain' => $domain, - 'subscriber' => $subscriber, - 'application' => $application, - 'destination' => $destination, - 'region' => $region, - 'connect' => intval($connect), - 'duration' => intval($min_duration) - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_discounts'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log = sprintf("Error: Mongo exception when inserting in billing_discounts: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } elseif ($ops == "3") { $query=sprintf( "delete from billing_discounts where gateway = '%s' and reseller_id = '%s' and domain = '%s' and subscriber = '%s' and application = '%s' and destination = '%s' and region = '%s' ", addslashes($gateway), addslashes($reseller_id), addslashes($domain), addslashes($subscriber), addslashes($application), addslashes($destination), addslashes($region) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $deleted++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_discounts'); - $mongo_match = array( - 'reseller_id' => intval(reseller_id), - 'gateway' => $gateway, - 'domain' => $domain, - 'subscriber' => $subscriber, - 'application' => $application, - 'destination' => $destination, - 'region' => $region - ); - $mongo_table_rw->remove( - $mongo_match, - array("safe" => $self->mongo_safe) - ); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when deleting from billing_discounts: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } elseif ($ops == "2") { $query = sprintf( "select * from billing_discounts where gateway = '%s' and reseller_id = '%s' and domain = '%s' and subscriber = '%s' and application = '%s' and destination = '%s' and region = '%s' ", addslashes($gateway), addslashes($reseller_id), addslashes($domain), addslashes($subscriber), addslashes($application), addslashes($destination), addslashes($region) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->num_rows()) { $query = sprintf( "update billing_discounts set connect = '%s', duration = '%s', where gateway = '%s' and reseller_id = '%s' and domain = '%s' and subscriber = '%s' and application = '%s' and destination = '%s' and region = '%s' ", addslashes($connect), addslashes($duration), addslashes($gateway), addslashes($reseller_id), addslashes($domain), addslashes($subscriber), addslashes($application), addslashes($destination), addslashes($region) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows()) { $updated++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_match=array( - 'reseller_id' => intval(reseller_id), - 'gateway' => $gateway, - 'domain' => $domain, - 'subscriber' => $subscriber, - 'application' => $application, - 'destination' => $destination, - 'region' => $region - ); - $mongo_data=array( - 'reseller_id' => intval(reseller_id), - 'gateway' => $gateway, - 'domain' => $domain, - 'subscriber' => $subscriber, - 'application' => $application, - 'destination' => $destination, - 'region' => $region, - 'connect' => intval($connect), - 'duration' => intval($min_duration) - ); - $mongo_options = array( - "upsert" => true, - "safe" => $self->mongo_safe - ); - - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_discounts'); - $result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when updating billing_discounts: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } else { $query = sprintf( "insert into billing_discounts ( reseller_id, gateway, domain, subscriber, application, destination, region, connect, duration ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($gateway), addslashes($domain), addslashes($subscriber), addslashes($application), addslashes($destination), addslashes($region), addslashes($connect), addslashes($duration) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $inserted++; } else { $failed++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_data=array( - 'reseller_id' => intval(reseller_id), - 'gateway' => $gateway, - 'domain' => $domain, - 'subscriber' => $subscriber, - 'application' => $application, - 'destination' => $destination, - 'region' => $region, - 'connect' => intval($connect), - 'duration' => intval($min_duration) - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_discounts'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when inserting in billing_discounts: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } } else { $skipped++; } $this->showImportProgress($file); $i++; } if ($i) print "Read $i records\n"; if ($skipped) print "Skipped $skipped records\n"; if ($inserted) print "Inserted $inserted records\n"; if ($updated) print "Updated $updated records\n"; if ($deleted) print "Delete $deleted records\n"; $results = $inserted + $updated + $deleted; return $results; } private function ImportProfiles($file, $reseller = 0) { if (!$file || !is_readable($file) || !$fp = fopen($file, "r")) return false; $this->mustReload=true; $i=0; $inserted = 0; $updated = 0; $deleted = 0; print "Importing Profiles:\n"; while ($buffer = fgets($fp, 1024)) { $buffer=trim($buffer); $p = explode($this->delimiter, $buffer); $ops = trim($p[0]); $profile = trim($p[2]); $rate1 = trim($p[3]); $hour1 = trim($p[4]); $rate2 = trim($p[5]); $hour2 = trim($p[6]); $rate3 = trim($p[7]); $hour3 = trim($p[8]); $rate4 = trim($p[9]); $hour4 = trim($p[10]); if ($reseller) { $reseller_id = intval($reseller); } else { $reseller_id = intval($p[1]); } if (!$hour1) $hour1=0; if (!$hour2) $hour2=0; if (!$hour3) $hour3=0; if (!$hour4) $hour4=0; if ($ops=="1") { $query = sprintf( "insert into billing_profiles ( reseller_id, name, rate_name1, hour1, rate_name2, hour2, rate_name3, hour3, rate_name4, hour4 ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($profile), addslashes($rate1), addslashes($hour1), addslashes($rate2), addslashes($hour2), addslashes($rate3), addslashes($hour3), addslashes($rate4), addslashes($hour4) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $inserted++; } else { $failed++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'name' => $profile, - 'rate_name1' => $rate1, - 'hour1' => $hour1, - 'rate_name2' => $rate2, - 'hour2' => $hour2, - 'rate_name3' => $rate3, - 'hour3' => $hour3, - 'rate_name4' => $rate4, - 'hour4' => $hour4 - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_profiles'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when inserting in billing_profiles: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - } - } - } } elseif ($ops == "3") { $query = sprintf( "delete from billing_profiles where name = '%s' and reseller_id= '%s' ", addslashes($profile), addslashes($reseller_id) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $deleted++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_profiles'); - $mongo_match = array( - 'reseller_id' => intval(reseller_id), - 'name' => $name - ); - $mongo_table_rw->remove( - $mongo_match, - array("safe" => $self->mongo_safe) - ); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when deleting from billing_profiles: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } elseif ($ops == "2") { $query = sprintf( "select * from billing_profiles where name = '%s' and reseller_id= '%s' ", addslashes($profile), addslashes($reseller_id) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->num_rows()) { $query = sprintf( "update billing_profiles set rate_name1 = '%s', rate_name2 = '%s', rate_name3 = '%s', rate_name4 = '%s', hour1 = '%s', hour2 = '%s', hour3 = '%s', hour4 = '%s' where name = '%s' and reseller_id= '%s' \n", addslashes($rate1), addslashes($rate2), addslashes($rate3), addslashes($rate4), addslashes($hour1), addslashes($hour2), addslashes($hour3), addslashes($hour4), addslashes($profile), addslashes($reseller_id) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows()) { $updated++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_match = array( - 'reseller_id' => intval(reseller_id), - 'name' => $profile - ); - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'name' => $profile, - 'rate_name1' => $rate1, - 'hour1' => $hour1, - 'rate_name2' => $rate2, - 'hour2' => $hour2, - 'rate_name3' => $rate3, - 'hour3' => $hour3, - 'rate_name4' => $rate4, - 'hour4' => $hour4 - ); - - $mongo_options = array( - "upsert" => true, - "safe" => $self->mongo_safe - ); - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_profiles'); - $result = $mongo_table_rw->update($mongo_match, $mongo_data, $mongo_options); - } catch (Exception $e) { - $log=sprintf("Error: Mongo exception when updating billing_profiles: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - return false; - } - } - } } else { $query = sprintf( "insert into billing_profiles ( reseller_id, name, rate_name1, hour1, rate_name2, hour2, rate_name3, hour3, rate_name4, hour4 ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )", addslashes($reseller_id), addslashes($profile), addslashes($rate1), addslashes($hour1), addslashes($rate2), addslashes($hour2), addslashes($rate3), addslashes($hour3), addslashes($rate4), addslashes($hour4) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows() >0) { $inserted++; } else { $failed++; } - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_rw) { - $mongo_data = array( - 'reseller_id' => intval(reseller_id), - 'name' => $profile, - 'rate_name1' => $rate1, - 'hour1' => $hour1, - 'rate_name2' => $rate2, - 'hour2' => $hour2, - 'rate_name3' => $rate3, - 'hour3' => $hour3, - 'rate_name4' => $rate4, - 'hour4' => $hour4 - ); - - try { - $mongo_table_rw = $this->mongo_db_rw->selectCollection('billing_profiles'); - $mongo_table_rw->insert($mongo_data, array("safe" => $self->mongo_safe)); - } catch (Exception $e) { - $log = sprintf("Error: Mongo exception when inserting in billing_profiles: %s", $e->getMessage()); - print $log; - syslog(LOG_NOTICE, $log); - } - } - } } } $this->showImportProgress($file); $i++; } if ($i) print "Read $i records\n"; if ($inserted) print "Inserted $inserted records\n"; if ($updated) print "Updated $updated records\n"; if ($deleted) print "Delete $deleted records\n"; $results = $inserted + $updated + $deleted; return $results; } public function LoadRatingTables() { $log = sprintf( "Memory usage: %0.2fMB, memory limit: %sB", memory_get_usage() / 1024 / 1024, ini_get('memory_limit') ); syslog(LOG_NOTICE, $log); $loaded['profiles'] = $this->LoadProfilesTable(); $loaded['ratesHistory'] = $this->LoadRatesHistoryTable(); $loaded['holidays'] = $this->LoadHolidaysTable(); $loaded['enumTlds'] = $this->LoadENUMtldsTable(); foreach (array_keys($loaded) as $_load) { syslog(LOG_NOTICE, "Loaded $loaded[$_load] $_load into memory"); } $log = sprintf( "Memory usage: %0.2fMB, memory limit: %sB", memory_get_usage() / 1024 / 1024, ini_get('memory_limit') ); syslog(LOG_NOTICE, $log); return $loaded; } private function LoadENUMtldsTable() { - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_ro) { - // mongo backend - try { - $table = $this->mongo_db_ro->selectCollection('billing_enum_tlds'); - $cursor = $table->find()->slaveOkay(); - } catch (Exception $e) { - $log = sprintf("

Caught Mongo exception in LoadENUMtldsTable(): %s", $e->getMessage()); - syslog(LOG_NOTICE, $log); - return 0; - } - - $i=0; - foreach ($cursor as $result) { - if ($result['enum_tld']) { - $i++; - $_app=$result['application']; - if (!$_app) $_app='audio'; - - $_ENUMtlds[$result['enum_tld']] = array( - "discount" => $result['discount'], - "e164_regexp" => $result['e164_regexp'] - ); - } - } - $this->ENUMtlds = $_ENUMtlds; - $this->ENUMtldsCount = $i; - return $i; - } else { - $log = sprintf("

Error: mongo db is not initialized in LoadENUMtldsTable()"); - syslog(LOG_NOTICE, $log); - return 0; - } - } - $query = "select * from billing_enum_tlds"; if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $i=0; $rows=$this->db->num_rows(); while ($this->db->next_record()) { if ($this->db->Record['enum_tld']) { $i++; $_app=$this->db->Record['application']; if (!$_app) $_app='audio'; $_ENUMtlds[$this->db->Record['enum_tld']] = array( "discount" => $this->db->Record['discount'], "e164_regexp" => $this->db->Record['e164_regexp'] ); } } $this->ENUMtlds = $_ENUMtlds; $this->ENUMtldsCount = $i; return $i; } private function LoadRatesHistoryTable() { - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_ro) { - // mongo backend - try { - $table = $this->mongo_db_ro->selectCollection('billing_rates_history'); - $cursor = $table->find()->slaveOkay(); - } catch (Exception $e) { - $log = sprintf("

Caught Mongo exception in LoadRatesHistoryTable(): %s", $e->getMessage()); - syslog(LOG_NOTICE, $log); - return 0; - } - - $i=0; - foreach ($cursor as $result) { - $i++; - if ($result['name'] && $result['destination']) { - $i++; - $_app=$result['application']; - if (!$_app) $_app='audio'; - - preg_match("/^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$/", $result['startDateTimestamp'], $m); - $startDate = mktime($m[4], $m[5], $m[6], $m[2], $m[3], $m[1]); - preg_match("/^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$/", $result['endDateTimestamp'], $m); - $endDate = mktime($m[4], $m[5], $m[6], $m[2], $m[3], $m[1]); - - $_rates[$result['name']][$result['destination']][$_app][$result['id']] = array( - "connectCost" => $result['connectCost'], - "durationRate" => $result['durationRate'], - "connectCostIn" => $result['connectCostIn'], - "durationRateIn" => $result['durationRateIn'], - "increment" => $result['increment'], - "min_duration" => $result['min_duration'], - "startDate" => $startDate, - "endDate" => $endDate - ); - } - } - $this->ratesHistory=$_rates; - $this->ratesHistoryCount=$i; - return $i; - } else { - $log = sprintf("

Error: mongo db is not initialized in LoadRatesHistoryTable()"); - syslog(LOG_NOTICE, $log); - return 0; - } - } - $query = "select *, UNIX_TIMESTAMP(startDate) as startDateTimestamp, UNIX_TIMESTAMP(endDate) as endDateTimestamp from billing_rates_history order by name ASC,destination ASC,startDate DESC"; if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $i=0; $rows=$this->db->num_rows(); while ($this->db->next_record()) { if ($this->db->Record['name'] && $this->db->Record['destination']) { $i++; $_app = $this->db->Record['application']; if (!$_app) $_app='audio'; $_rates[$this->db->Record['name']][$this->db->Record['destination']][$_app][$this->db->Record['id']]= array( "connectCost" => $this->db->Record['connectCost'], "durationRate" => $this->db->Record['durationRate'], "connectCostIn" => $this->db->Record['connectCostIn'], "durationRateIn" => $this->db->Record['durationRateIn'], "increment" => $this->db->Record['increment'], "min_duration" => $this->db->Record['min_duration'], "startDate" => $this->db->Record['startDateTimestamp'], "endDate" => $this->db->Record['endDateTimestamp'] ); } } $this->ratesHistory = $_rates; $this->ratesHistoryCount = $i; return $i; } private function LoadProfilesTable() { - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_ro) { - // mongo backend - try { - $table = $this->mongo_db_ro->selectCollection('billing_profiles'); - $cursor = $table->find()->slaveOkay(); - } catch (Exception $e) { - $log = sprintf("

Caught Mongo exception in LoadProfilesTable(): %s", $e->getMessage()); - syslog(LOG_NOTICE, $log); - return 0; - } - - $i=0; - foreach ($cursor as $result) { - $i++; - if ($result['name'] && $result['hour1'] > 0) { - $_profiles[$result['name']] = array( - "rate_name1" => $result['rate_name1'], - "hour1" => $result['hour1'], - "rate_name2" => $result['rate_name2'], - "hour2" => $result['hour2'], - "rate_name3" => $result['rate_name3'], - "hour3" => $result['hour3'], - "rate_name4" => $result['rate_name4'], - "hour4" => $result['hour4'], - ); - } - } - $this->profiles=$_profiles; - return $i; - } else { - $log = sprintf("

Error: mongo db is not initialized in LoadProfilesTable()"); - syslog(LOG_NOTICE, $log); - return 0; - } - } - $query = "select * from billing_profiles order by name"; if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $i=0; while ($this->db->next_record()) { $i++; if ($this->db->Record['name'] && $this->db->Record['hour1'] > 0) { $_profiles[$this->db->Record['name']]= array( "rate_name1" => $this->db->Record['rate_name1'], "hour1" => $this->db->Record['hour1'], "rate_name2" => $this->db->Record['rate_name2'], "hour2" => $this->db->Record['hour2'], "rate_name3" => $this->db->Record['rate_name3'], "hour3" => $this->db->Record['hour3'], "rate_name4" => $this->db->Record['rate_name4'], "hour4" => $this->db->Record['hour4'], ); } } $this->profiles=$_profiles; return $i; } private function LoadHolidaysTable() { - if ($this->database_backend == 'mongo') { - if ($this->mongo_db_ro) { - // mongo backend - try { - $table = $this->mongo_db_ro->selectCollection('billing_holidays'); - $cursor = $table->find()->slaveOkay(); - } catch (Exception $e) { - $log = sprintf("

Caught Mongo exception in LoadHolidaysTable(): %s", $e->getMessage()); - syslog(LOG_NOTICE, $log); - return 0; - } - - $i=0; - foreach ($cursor as $result) { - $i++; - if ($result['day']) { - $i++; - $_holidays[$result['day']]++; - } - } - $this->holidays=$_holidays; - return $i; - } else { - $log = sprintf("

Error: mongo db is not initialized in LoadHolidaysTable()"); - syslog(LOG_NOTICE, $log); - return 0; - } - } - $query="select * from billing_holidays order by day"; if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $i=0; while ($this->db->next_record()) { if ($this->db->Record['day']) { $i++; $_holidays[$this->db->Record['day']]++; } } $this->holidays=$_holidays; return $i; } public function checkRatingEngineConnection() { if ($this->settings['socketIPforClients'] && $this->settings['socketPort'] && $fp = fsockopen($this->settings['socketIPforClients'], $this->settings['socketPort'], $errno, $errstr, 2) ) { fclose($fp); return true; } return false; } function showCustomers($filter) { return true; foreach (array_keys($this->customers) as $key) { if (strlen($filter)) { if (preg_match("/$filter/", $key)) { $customers = $customers.$key."\n"; } } else { $customers = $customers.$key."\n"; } } return $customers; } public function showProfiles() { foreach (array_keys($this->profiles) as $key) { $profiles=$profiles.$key."\n"; } return $profiles; } public function showENUMtlds() { foreach (array_keys($this->ENUMtlds) as $key) { $ENUMtlds=$ENUMtlds.$key."\n"; } return $ENUMtlds; } private function scanFilesForImport($dir) { $import_dirs[$this->cvs_import_dir] = array( 'path' => $this->cvs_import_dir, 'reseller' => 0 ); if ($handle = opendir($this->cvs_import_dir)) { while (false !== ($filename = readdir($handle))) { $reseller=0; if ($filename == "." || $filename == "..") continue; $fullPath = $this->cvs_import_dir."/".$filename; if (is_dir($fullPath) && is_numeric($filename)) { $reseller = $filename; $import_dirs[$fullPath]=array( 'path' => $fullPath, 'reseller'=> $reseller ); } } } foreach (array_keys($import_dirs) as $_dir) { if ($handle = opendir($_dir)) { while (false !== ($filename = readdir($handle))) { if ($filename != "." && $filename != "..") { foreach ($this->importFilesPatterns as $_pattern) { if (strstr($filename, $_pattern) && preg_match("/\.csv$/", $filename)) { $fullPath = $_dir."/".$filename; if ($content = file_get_contents($fullPath)) { $watermark = $filename."-".md5($content); if ($this->hasFileBeenImported($filename, $watermark)) { $this->previously_imported_files++; break; } $this->filesToImport[$filename] = array( 'name' => $filename, 'watermark' => $watermark, 'type' => $_pattern, 'path' => $fullPath, 'reseller' => $import_dirs[$_dir]['reseller'] ); } break; } } } } } } } private function hasFileBeenImported($filename, $watermark) { $query = sprintf( "select * from log where url = '%s'\n", addslashes($watermark) ); if ($this->db->query($query)) { if ($this->db->num_rows()) { $this->db->next_record(); /* $log=sprintf ("File %s has already been imported at %s.\n",$filename,$this->db->f('date')); syslog(LOG_NOTICE, $log); print $log; */ return true; } else { return false; } } else { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } } private function logImport($dir, $filename, $watermark, $results = 0, $reseller = 0) { $query = sprintf( "insert into log ( date, login, ip, url, results, description, datasource, reseller_id ) values ( NOW(), 'ImportScript', 'localhost', '%s', '%s', 'Imported %s', '%s', %d )", addslashes($watermark), addslashes($results), addslashes($filename), addslashes($dir), addslashes($reseller) ); $log = sprintf( "Imported file %s, %d records have been affected\n", $filename, $results ); syslog(LOG_NOTICE, $log); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } } function showImportProgress($filename = 'unspecified', $increment = 5000) { $this->importIndex++; if ($this->importIndex == $increment) { printf("Loaded %d records from %s\n", $this->importIndex, $filename); flush(); $this->importIndex=0; } } function createRatingTable($name) { if ($name) { $table='billing_rates_'.$name; } else { $table='billing_rates_default'; } $query = sprintf( "create table %s select * from billing_rates where name = '%s'\n", addslashes($table), addslashes($name) ); if ($this->db->query($query)) { $query = sprintf( "alter table %s add index rate_idx (name)", addslashes($table) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); } $query = sprintf( "alter table %s add index destination_idx (destination)", addslashes($table) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); } printf("Created table %s\n", $table); return true; } else { return false; } } public function splitRatingTable() { $query = "select count(*) as c from billing_rates"; if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $this->db->next_record(); $rows=$this->db->f('c'); $query="select distinct(name) from billing_rates order by name ASC"; if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } while ($this->db->next_record()) { $rate_names[]=$this->db->f('name'); } foreach ($rate_names as $name) { if (!$name) $name='default'; $table="billing_rates_".$name; $query = sprintf("drop table if exists %s", addslashes($table)); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $query = sprintf( "create table %s select * from billing_rates where name = '%s'\n", addslashes($table), addslashes($name) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } else { $query = sprintf( "alter table %s add index rate_idx (name)", addslashes($table) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $query = sprintf( "alter table %s add index destination_idx (destination)", addslashes($table) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $query = sprintf("select count(*) as c from %s", addslashes($table)); $this->db->query($query); $this->db->next_record(); $records=$this->db->f('c'); $created_records=$created_records+$records; $progress=100*$created_records/$rows; printf( "Created table %s with %s records (%.1f %s)\n", $table, $records, $progress, '%' ); } } return true; } public function updateTable() { global $auth; $loginname=$auth->auth["uname"]; foreach ($this->web_elements as $_el) { ${$_el}= $_REQUEST[$_el]; } if (!$table) return false; if ($this->readonly) { return true; } // Init table structure if (!is_array($this->tables[$table]['exceptions'])) $this->tables[$table]['exceptions']=array(); if (!is_array($this->tables[$table]['keys'])) $this->tables[$table]['keys']=array(); if (!is_array($this->tables[$table]['fields'])) $this->tables[$table]['fields']=array(); $metadata = $this->db->metadata($table = "$table"); $cc = count($metadata); // end init table structure if ($web_task =="update") { $affected_rows=0; if ($subweb_task == "Update") { if ($this->checkValues($table, $_REQUEST)) { $update_set=''; $k=0; while ($k < $cc) { $k++; $Fname=$metadata[$k]['name']; if (!$Fname) continue; $value=$_REQUEST[$Fname]; if ($this->tables[$table]['fields'][$Fname]['readonly']) { continue; } if (in_array($Fname, $this->tables[$table]['exceptions'])) { continue; } if (in_array($Fname, $this->tables[$table]['keys'])) { continue; } if ($kkk > 0) { $comma = ","; } else { $comma = ""; } if (!$this->tables[$table]['skip_math'] && preg_match("/^([\+\-\*\/])(.*)$/", $value, $sign)) { $update_set .= $comma.addslashes($Fname)."= ROUND(".addslashes($Fname). " ".$sign[1]. "'".$sign[2]."')"; } else { $update_set .= $comma.addslashes($Fname)."='".addslashes($value)."'"; } $kkk++; } $k=0; while ($k < $cc) { if ($metadata[$k]['name'] == 'change_date') { $update_set .= sprintf("%s %s = NOW() ", $comma, addslashes($metadata[$k]['name'])); break; } $k++; } $log_entity=" id = $id "; $where = sprintf(" id = '%s' and %s", addslashes($id), $this->whereResellerFilter); if ($table == "billing_rates") { if ($this->settings['split_rating_table']) { $rate_table_affected = array(); $query_r = "select distinct (name) from billing_rates where". $where; if ($this->db->query($query_r)) { while ($this->db->next_record()) { $rate_tables_affected[]='billing_rates_'.$this->db->f('name'); } } else { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); } } } elseif ($table=="prepaid") { register_shutdown_function("unLockTables", $this->db); if ($this->db->query("lock table prepaid write")) { $query_q = sprintf( "select * from prepaid where account = '%s'", addslashes($account) ); if ($this->db->query($query_q) && $this->db->num_rows()) { $this->db->next_record(); $old_balance=$this->db->f('balance'); } $this->db->query("unlock tables"); } } $query = sprintf( "update %s set %s where %s ", addslashes($table), $update_set, $where ); if ($this->db->query($query)) { $affected_rows=$this->db->affected_rows(); if ($affected_rows) { if ($table=="prepaid") { list($username, $domain) = explode("@", $account); $value=$balance-$old_balance; if (floatval($balance) != floatval($old_balance)) { $query = sprintf( "insert into prepaid_history (username,domain,action,description,value,balance,date,reseller_id) values ('%s','%s','Set balance','Manual update','%s','%s',NOW(),%d)", addslashes($username), addslashes($domain), addslashes($value), addslashes($balance), $this->CDRTool['filter']['reseller'] ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); } } } elseif ($table=='billing_rates') { if ($this->settings['split_rating_table']) { foreach ($rate_tables_affected as $extra_rate_table) { $query_u = sprintf( "update %s set %s where %s ", addslashes($extra_rate_table), $update_set, $where ); if (!$this->db->query($query_u)) { $log = sprintf( "Database error for query %s: %s (%s)", $query_u, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); } } } } if (in_array($table, $this->requireReload)) { if (!$this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'")) { printf( "Database error: %s (%s)", $this->db->Error, $this->db->Errno ); } } } } else { printf( "Database error for query '%s': %s (%s)", $query, $this->db->Error, $this->db->Errno ); } } else { print "

Correct the values and try again."; } } elseif ($subweb_task == "Update selection") { $k=0; $kkk=0; $update_set=''; while ($k < $cc) { $k++; $Fname=$metadata[$k]['name']; $value=$_REQUEST[$Fname]; if (!strlen($value)) continue; if ($this->tables[$table]['fields'][$Fname]['readonly']) { continue; } if (in_array($Fname, $this->tables[$table]['exceptions'])) { continue; } if (in_array($Fname, $this->tables[$table]['keys'])) { continue; } if ($kkk > 0) { $comma = ","; } else { $comma=""; } if ($value == "NULL") { $value=""; } if (preg_match("/^([\+\-\*\/])(.*)$/", $value, $sign)) { $update_set .= $comma.$Fname." = ROUND(".$Fname. " ".$sign[1]. "'".$sign[2]."')"; } else { $update_set .= $comma.$Fname." = '".$value."'"; } $kkk++; } $where = $this->whereResellerFilter; if ($kkk) { // reconstruct where clause to apply all changes to selection // build where clause // Search build for each field $j=0; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if (!in_array($Fname, $this->tables[$table]['exceptions'])) { $f_name="search_".$Fname; $value=$_REQUEST[$f_name]; if (preg_match("/^([<|>]+)(.*)$/", $value, $likes)) { $like=$likes[1]; $likewhat=$likes[2]; $quotes=""; } else { $like="like"; $likewhat=$value; $quotes="'"; } if (strlen($value)) { $where .= " and $Fname $like $quotes".$likewhat."$quotes"; $t++; } } $j++; } if ($table == 'billing_rates') { if ($this->settings['split_rating_table']) { $rate_table_affected = array(); $query_r = "select distinct (name) from billing_rates where". $where; if ($this->db->query($query_r)) { while ($this->db->next_record()) { $rate_tables_affected[] = 'billing_rates_'.$this->db->f('name'); } } else { printf( "Database error: %s (%s)", $this->db->Error, $this->db->Errno ); } } } $query = sprintf( "update %s set %s where %s ", addslashes($table), $update_set, $where ); if ($this->db->query($query)) { $affected_rows=$this->db->affected_rows(); if ($affected_rows) { if ($table == 'billing_rates') { if ($this->settings['split_rating_table']) { foreach ($rate_tables_affected as $extra_rate_table) { $query_u = sprintf( "update %s set %s where %s ", addslashes($extra_rate_table), $update_set, $where ); if (!$this->db->query($query_u)) { printf( "Database error for %s: %s (%s)", $query_u, $this->db->Error, $this->db->Errno ); } } } } if (in_array($table, $this->requireReload)) { $this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'"); } } } else { printf("Database error: %s", $this->db->Error); } } } elseif ($subweb_task == "Delete selection") { if ($confirmDelete) { // reconstruct where clause to apply all changes to selection // build where clause // Search build for each field $where = $this->whereResellerFilter; $j=0; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if (!in_array($Fname, $this->tables[$table]['exceptions'])) { $f_name="search_".$Fname; $value=$_REQUEST[$f_name]; if (preg_match("/^([<|>]+)(.*)$/", $value, $likes)) { $like = $likes[1]; $likewhat = $likes[2]; $quotes = ""; } else { $like = "like"; $likewhat = $value; $quotes = "'"; } if (strlen($value)) { $where .= " and $Fname $like $quotes".$likewhat."$quotes"; $t++; } } $j++; } if ($table == 'billing_rates') { if ($this->settings['split_rating_table']) { $rate_table_affected=array(); $query_r = "select distinct (name) from billing_rates where". $where; if ($this->db->query($query_r)) { while ($this->db->next_record()) { $rate_tables_affected[] = 'billing_rates_'.$this->db->f('name'); } } else { printf( "Database error: %s (%s)", $this->db->Error, $this->db->Errno ); } } } $query = sprintf( "delete from %s where %s", addslashes($table), $where ); if ($this->db->query($query)) { $affected_rows = $this->db->affected_rows(); if ($affected_rows) { if ($table == 'billing_rates') { if ($this->settings['split_rating_table']) { foreach ($rate_tables_affected as $extra_rate_table) { $query_u = sprintf( "delete from %s where %s ", addslashes($extra_rate_table), $where ); if (!$this->db->query($query_u)) { printf( "Database error for %s: %s (%s)", $query_u, $this->db->Error, $this->db->Errno ); } } } } if (in_array($table, $this->requireReload)) { $this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'"); } } } else { printf( "Database error: %s", $this->db->Error ); } unset($confirmDelete); } else { print "

"; print "Please confirm the deletion by pressing the Delete button again. "; print ""; print ""; } } elseif ($subweb_task == "Copy rate" && strlen($fromRate) && strlen($toRate)) { $toRate=preg_replace("/%/", "", $toRate); if ($confirmCopy) { if ($toRate == 'history') { $values = sprintf( "(reseller_id,name,destination,application,connectCost,durationRate,connectCostIn,durationRateIn,startDate,endDate) select billing_rates.reseller_id, '%s', billing_rates.destination, billing_rates.application, billing_rates.connectCost, billing_rates.durationRate, billing_rates.connectCostIn, billing_rates.durationRateIn, NOW(), NOW() from billing_rates ", addslashes($fromRate) ); } else { $values = sprintf( "(reseller_id,name,destination,application,connectCost,durationRate,connectCostIn,durationRateIn) select billing_rates.reseller_id, '%s', billing_rates.destination, billing_rates.application, billing_rates.connectCost, billing_rates.durationRate, billing_rates.connectCostIn, billing_rates.durationRateIn from billing_rates ", addslashes($toRate) ); } $where = $this->whereResellerFilter; $j=0; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if (!in_array($Fname, $this->tables[$table]['exceptions'])) { $f_name="search_".$Fname; $value=$_REQUEST[$f_name]; if (preg_match("/^([<|>]+)(.*)$/", $value, $likes)) { $like=$likes[1]; $likewhat=$likes[2]; $quotes=""; } else { $like="like"; $likewhat=$value; $quotes="'"; } if (strlen($value)) { $where .= sprintf( " and %s %s %s%s%s ", addslashes($Fname), $like, $quotes, addslashes($likewhat), $quotes ); $t++; } } $j++; } if ($toRate == 'history') { $query="insert into billing_rates_history $values where $where"; } else { $query="insert into billing_rates $values where $where"; } if ($this->db->query($query)) { $affected_rows=$this->db->affected_rows(); if ($affected_rows) { print "$affected_rows rates copied. "; if ($table == 'billing_rates') { if ($this->settings['split_rating_table']) { $query = sprintf( "create table billing_rates_%s select * from billing_rates where %s ", addslashes($toRate), $where ); if (!$this->db->query($query)) { printf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); } } } if (in_array($table, $this->requireReload)) { $this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'"); } } if ($toRate == 'history') { // Switch to history $table = 'billing_rates_history'; // Init table structure $this->tables[$table]['exceptions']= $this->tables[$table]['exceptions']; $this->tables[$table]['keys'] = $this->tables[$table]['keys']; $this->tables[$table]['fields'] = $this->tables[$table]['fields']; $metadata = $this->db->metadata($table = "$table"); $cc = count($metadata); // end init table structure } unset($confirmCopy); } else { printf("Database error: %s", $this->db->Error); } $log_entity="rate=$toRate"; } else { print "

"; print "Please confirm the copy of rate $fromRate to $toRate. "; print ""; } } elseif ($subweb_task == "Insert") { //print "

Insert

"; if ($this->checkValues($table, $_REQUEST)) { $query=sprintf("insert into %s ( ", addslashes($table)); $k=1; $kkk=0; while ($k < $cc) { $Fname=$metadata[$k]['name']; if (!in_array($Fname, $this->tables[$table]['exceptions'])) { if ($kkk > 0) { $comma = ","; } else { $comma=""; } $query .= $comma.addslashes($Fname); $kkk++; } $k++; } $query .= ") values ( "; $k=1; $kkk=0; while ($k < $cc) { $Fname=$metadata[$k]['name']; $value=$_REQUEST[$Fname]; if (!in_array($Fname, $this->tables[$table]['exceptions'])) { if ($kkk > 0) { $comma = ","; } else { $comma=""; } if ($Fname == 'reseller_id' && $this->CDRTool['filter']['reseller']) { $query .= $comma."'".addslashes($this->CDRTool['filter']['reseller'])."'"; } else { $query .= $comma."'".addslashes($value)."'"; } $kkk++; } $k++; } $query .= ") "; $k=1; while ($k < $cc) { $Fname=$metadata[$k]['name']; $value=$_REQUEST[$Fname]; if (in_array($Fname, $this->tables[$table]['keys'])) { if ($value == "") { $Fname_print_insert = substr($Fname, 4); print "$Fname_print_insert = ????
"; $empty_insert = 1; } } $k++; } if (!$empty_insert) { if ($this->db->query($query)) { $affected_rows=$this->db->affected_rows(); if ($affected_rows) { $this->db->query("select LAST_INSERT_ID() as lid"); $this->db->next_record(); $log_entity = sprintf("id=%s", $this->db->f('lid')); if (in_array($table, $this->requireReload)) { $this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'"); } } } else { printf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); } } else { print " Error: The insert statement contains an empty key! "; } } else { print "

Correct the values and try again."; } } elseif ($subweb_task == "Delete") { if ($confirmDelete) { $query = sprintf( "delete from %s where id = '%s' and %s ", addslashes($table), addslashes($id), addslashes($this->whereResellerFilter) ); if ($this->db->query($query)) { $affected_rows=$this->db->affected_rows(); if ($affected_rows && in_array($table, $this->requireReload)) { $this->db->query("update settings set var_value= '1' where var_name = 'reloadRating'"); } $log_entity = sprintf("id=%s", $id); } else { printf("Database error: %s", $this->db->Error); } unset($confirmDelete); } else { $idForDeletion=$id; print "

"; print "Please confirm the deletion by pressing the Delete button again. "; print ""; print ""; } } elseif ($subweb_task == "Delete session" && $sessionId && $table=='prepaid') { $query = sprintf( "select active_sessions from %s where id = %d and %s", addslashes($table), addslashes($id), $this->whereResellerFilter ); if (!$this->db->query($query)) { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; } if (!$this->db->num_rows()) return; $this->db->next_record(); if (strlen($this->db->f('active_sessions'))) { // remove session $active_sessions=array(); $old_active_sessions = json_decode($this->db->f('active_sessions'), true); if (!count($old_active_sessions)) return; foreach (array_keys($old_active_sessions) as $_key) { if ($_key==$sessionId) continue; $active_sessions[$_key]=$old_active_sessions[$_key]; } } else { $active_sessions=array(); } $query = sprintf( "update %s set active_sessions = '%s', session_counter = %d where id = %d", addslashes($table), addslashes(json_encode($active_sessions)), count($active_sessions), addslashes($id) ); if ($this->db->query($query)) { return 1; } else { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); print $log; return 0; } } if ($affected_rows && $table!="prepaid") { $log_query = sprintf( "insert into log (date,login,ip,datasource,results,description,reseller_id) values (NOW(),'%s','%s','Rating','%d','%s in table %s %s',%d)", addslashes($loginname), addslashes($_SERVER['REMOTE_ADDR']), addslashes($affected_rows), addslashes($subweb_task), addslashes($table), addslashes($log_entity), addslashes($this->CDRTool['filter']['reseller']) ); $this->db->query($log_query); } } } public function showTable() { $PHP_SELF=$_SERVER['PHP_SELF']; foreach ($this->web_elements as $_el) { ${$_el}= $_REQUEST[$_el]; } if ($this->table == 'prepaid_cards') { print "

Prepaid card generator"; } // Init table structure if (!is_array($this->tables[$this->table]['exceptions'])) $this->tables[$this->table]['exceptions']=array(); if (!is_array($this->tables[$this->table]['keys'])) $this->tables[$this->table]['keys']=array(); if (!is_array($this->tables[$this->table]['fields'])) $this->tables[$this->table]['fields']=array(); if ($this->table=='prepaid' && strlen($_REQUEST['search_session_counter'])) { $this->readonly=true; } if ($this->readonly) { $this->tables[$this->table]['readonly']=1; } $metadata = $this->db->metadata($this->table); $cc = count($metadata); // end init table structure // // delimiter for exporting records if ($this->settings['csv_delimiter']) { $delimiter=$this->settings['csv_delimiter']; } else { $delimiter=","; } $query = sprintf( "select count(*) as c from %s where %s", addslashes($this->table), $this->whereResellerFilter ); $t=0; $j=0; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; $class=$metadata[$j]['class']; if (!in_array($Fname, $this->tables[$this->table]['exceptions'])) { $f_name="search_".$Fname; $value=$_REQUEST[$f_name]; if (preg_match("/^([<|>]+)(.*)$/", $value, $likes)) { $like=$likes[1]; $likewhat=$likes[2]; $quotes=""; } else { $like="like"; $likewhat=$value; $quotes="'"; } if (strlen($value)) { $where .= sprintf( " and %s %s %s%s%s ", addslashes($Fname), $like, $quotes, addslashes($likewhat), $quotes ); $t++; } } $j++; } $query .= $where; $this->db->query($query); $this->db->next_record(); $rows=$this->db->Record['c']; if (!$export) { print " "; if ($this->csv_import[$this->table]) { print "
"; if ($rows == 0) { print "No records found. "; } else { print "$selectie $rows records found. "; } if ($this->settings['socketIPforClients'] && $this->settings['socketPort']) { $engineAddress = $this->settings['socketIPforClients'].":".$this->settings['socketPort']; if ($this->checkRatingEngineConnection()) { print " | Rating engine running at $engineAddress"; } else { print " | Cannot connect to rating engine $engineAddress"; } } print " | Rating documentation"; print "
"; printf( "
Select file Change Remove
", $this->table, $this->table ); print "
"; } else { print ""; } print "
"; $j=0; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if (!in_array($Fname, $this->tables[$this->table]['exceptions'])) { $SEARCH_NAME="search_".$Fname; $value=$_REQUEST[$SEARCH_NAME]; print ""; } $j++; } if ($this->table!=='prepaid_cards') { printf( " ", $this->table, $this->csv_export[$this->table], $this->csv_export[$this->table] ); } if ($this->settings['socketIPforClients'] && $this->settings['socketPort']) { if ($ReloadRatingTables) { reloadRatingEngineTables(); } else { $this->db->query("select var_value from settings where var_name = 'reloadRating' and var_value='1'"); if ($this->db->num_rows()) { print "table>Reload rating tables"; } } } print "
"; } else { $this->maxrowsperpage = 10000000; } if (!$next) { $i=0; $next=0; } else { $i=intval($next); } $j=0; $z=0; if ($rows > $this->maxrowsperpage) { $maxrows = $this->maxrowsperpage + $next; if ($maxrows > $rows) { $maxrows=$rows; $prev_rows=$maxrows; } } else { $maxrows=$rows; } if (!$order && $this->tables[$this->table]['order']) { $order = sprintf( " order by %s ", addslashes($this->tables[$this->table]['order']) ); } $query = sprintf( "select * from %s where (1=1) %s and %s %s limit %d, %d", addslashes($this->table), $where, $this->whereResellerFilter, $order, intval($i), intval($this->maxrowsperpage) ); $this->db->query($query); $num_fields=$this->db->num_fields(); $k=0; if (!$export) { if ($this->table=='prepaid') { print " "; } else { print "
"; } } while ($k < $cc) { $th = $metadata[$k]['name']; if (!in_array($th, $this->tables[$this->table]['exceptions'])) { if ($this->tables[$this->table]['fields'][$th]['name']) { $th=$this->tables[$this->table]['fields'][$th]['name']; } else { $th=ucfirst($th); } if (!$export) { print ""; } else { if ($k) { printf("%s%s", $delimiter, $th); } else { print "Ops"; } } $t_columns++; } $k++; } if ($export) { print "\n"; } if (!$export) { print " "; $t_columns=$t_columns+2; // SEARCH FORM print " "; // Search form print " "; $j=0; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if (!in_array($Fname, $this->tables[$this->table]['exceptions'])) { $SEARCH_NAME = "search_".$Fname; $value = $_REQUEST[$SEARCH_NAME]; if ($value != "") { $selection_made=1; } $maxlength=$size; if ($this->tables[$this->table]['fields'][$Fname]['size']) { $field_size = $this->tables[$this->table]['fields'][$Fname]['size']; } else { $field_size = $el_size; } $class=$this->tables[$this->table]['fields'][$Fname]['class']; if (!in_array($Fname, $this->tables[$this->table]['keys'])) { if (!$class) { $class = "span1"; } print ""; } else { print ""; } } $j++; } printf( " ", $PHP_SELF ); print " "; //print " // // // //"; if ($selection_made && !$this->tables[$this->table]['readonly']) { // Update all form print " "; $j=0; print " "; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if ($this->tables[$this->table]['fields'][$Fname]['size']) { $field_size=$this->tables[$this->table]['fields'][$Fname]['size']; } else { $field_size=$el_size; } $class=$this->tables[$this->table]['fields'][$Fname]['class']; if (!in_array($Fname, $this->tables[$this->table]['exceptions'])) { if (!in_array($Fname, $this->tables[$this->table]['keys'])) { if (!$class) { $class="span1"; } print ""; } else { print ""; } } $j++; } $j=0; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if (!in_array($Fname, $this->tables[$this->table]['exceptions'])) { $SEARCH_NAME="search_".$Fname; $value=$_REQUEST[$SEARCH_NAME]; print ""; } $j++; } if ($subweb_task=="Delete selection" && !$confirmDelete) { print " "; } elseif (!$this->tables[$this->table]['readonly']) { // Insert form $j=0; print " "; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if ($this->tables[$this->table]['fields'][$Fname]['size']) { $field_size=$this->tables[$this->table]['fields'][$Fname]['size']; } else { $field_size=$el_size; } $class=$this->tables[$this->table]['fields'][$Fname]['class']; if (!in_array($Fname, $this->tables[$this->table]['exceptions'])) { if (!in_array($Fname, $this->tables[$this->table]['keys'])) { if (!$class) { $class='span1'; } print ""; } else { print ""; } } $j++; } $j=0; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if (!in_array($Fname, $this->tables[$this->table]['exceptions'])) { $SEARCH_NAME = "search_".$Fname; $value = $_REQUEST[$SEARCH_NAME]; print ""; } $j++; } print " "; //print " // // // //"; } } while ($i < $maxrows) { $this->db->next_record(); $id = $this->db->f('id'); $status = $this->db->f('status'); $found = $i+1; if (!$export) { print " "; if ($this->table == 'prepaid') { $active_sessions = json_decode($this->db->f('active_sessions'), true); if (!isset($active_sessions)) { $active_sessions = array(); } $account=$this->db->f('account'); $extraInfo="
$thAction
Use _ to match one character and % to match any. Use > or < to find greater or smaller values.
  "; print("
"; print "

Use + or - to add/substract from curent values. Use * or / to multiply/divide curent values.
 "; print ""; print ""; print " ($rows records)"; } elseif (!$this->tables[$this->table]['readonly']) { if ($this->table == "billing_rates" && strlen($_REQUEST['search_name'])) { if ($subweb_task=="Copy rate" && !$confirmCopy) { print ""; print ""; } else { print ""; print "
"; } print " "; printf(" id %s to", $_REQUEST['search_name']); $query = sprintf( "select distinct(name) as name from billing_rates where name like '%s' order by name DESC limit 1", addslashes($_REQUEST['search_name']) ); $this->db1->query($query); $this->db1->next_record(); $_rateName = $this->db1->f('name'); $_rateName = preg_replace("/%/", "", $_rateName); if (preg_match("/^(.*)_(\d+)$/", $_rateName, $m)) { $_idx = $m[2] + 1; $newRateName = $m[1]."_".$_idx; } else { $newRateName = $_rateName."_1"; } printf( "", $_REQUEST['search_name'] ); $selected_newtable[$toRate]='selected'; printf( "", $newRateName, $selected_newtable[$newRateName], $newRateName, $selected_newtable['history'] ); } else { print "
"; print "
"; } } print "
table>
  table\">

"; $t=0; foreach (array_keys($active_sessions) as $_session) { $t++; $maxsessiontime=$active_sessions[$_session]['MaxSessionTime']; $extraInfo .= sprintf( "", $t, $_session ); $duration = time() - $active_sessions[$_session]['timestamp']; foreach (array_keys($active_sessions[$_session]) as $key) { if ($key=='timestamp') { $extraInfo .= sprintf( "", Date("Y-m-d H:i", $active_sessions[$_session]['timestamp']) ); $extraInfo .= sprintf( "", sec2hms($duration), $duration ); } else { $extraInfo .= sprintf( "", ucfirst($key), $active_sessions[$_session][$key] ); } } if ($maxsessiontime < $duration) { $extraInfo .= sprintf( "", $duration - $maxsessiontime ); $extraInfo .= ""; } //if (!$this->readonly) { //} } $extraInfo.=sprintf( "
%d. Session id%s
StartTime%s
Progress%s (%s s)
%s%s
Session expired since %d s
", $this->table, $next, $_session, $search_text ); } print "$found. "; } $j=0; while ($j < $this->db->num_fields()) { $value=$this->db->Record[$metadata[$j]['name']]; $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; $class=$metadata[$j]['class']; if ($this->tables[$this->table]['fields'][$Fname]['size']) { $field_size=$this->tables[$this->table]['fields'][$Fname]['size']; } else { $field_size=$el_size; } $class=$this->tables[$this->table]['fields'][$Fname]['class']; if ($this->tables[$this->table]['fields'][$Fname]['readonly']=="1") { $extra_form_els = "disabled=true"; } else { $extra_form_els = ""; } $class=$this->tables[$this->table]['fields'][$Fname]['class']; if (!in_array($Fname, $this->tables[$this->table]['exceptions'])) { if (!$export) { if (!in_array($Fname, $this->tables[$this->table]['keys']) && !$this->readonly) { if ($this->table == 'prepaid' && $Fname == 'session_counter' && $value) { if (count($active_sessions) > 1) { $session_counter_txt = sprintf("%d sessions", $value); } else { $session_counter_txt = sprintf("%d session", $value); } printf( "%s", $found, $session_counter_txt ); } else { if (!$class) { $class="span1"; } print " "; } } else { if ($this->table == 'prepaid' && $Fname == 'session_counter' && $value) { if (count($active_sessions) > 1) { $session_counter_txt = sprintf("%d sessions", $value); } else { $session_counter_txt = sprintf("%d session", $value); } printf( "%s", $found, $session_counter_txt ); } else { print "$value"; } } } else { if ($j) { printf("%s%s", $delimiter, $value); } else { print "2"; } } } $j++; } $j=0; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if (!in_array($Fname, $this->tables[$this->table]['exceptions'])) { $SEARCH_NAME = "search_".$Fname; $value=$_REQUEST[$SEARCH_NAME]; if (!$export) { print ""; } } $j++; } if ($export) { print "\n"; } if (!$export) { if (!$this->tables[$this->table]['readonly']) { if ($subweb_task=="Delete" && $idForDeletion == $id && !$confirmDelete) { print ""; print ""; print ""; } else { print "

"; print ""; } print " table> "; if ($extraInfo!='') { print " $extraInfo "; } } else { if ($this->table == 'prepaid') { print " $extraInfo "; } } } $i++; } if (!$export) { print " "; print "
"; if ($next != 0) { $show_next = $this->maxrowsperpage - $next; if ($show_next < 0) { $mod_show_next = $show_next - 2 * $show_next; print ""; } print " maxrowsperpage> table> "; $j=0; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if (!in_array($Fname, $this->tables[$this->table]['exceptions'])) { $SEARCH_NAME="search_".$Fname; $value=$_REQUEST[$SEARCH_NAME]; print " "; } $j++; } } print "
"; if ($rows>$this->maxrowsperpage && $rows!=$maxrows) { $show_next = $this->maxrowsperpage + $next; print " maxrowsperpage> table> "; $j=0; while ($j < $cc) { $Fname=$metadata[$j]['name']; $size=$metadata[$j]['len']; if (!in_array($Fname, $this->tables[$this->table]['exceptions'])) { $SEARCH_NAME="search_".$Fname; $value=$_REQUEST[$SEARCH_NAME]; print ""; } $j++; } print " "; } print "
"; print " "; } } private function checkValues($table, $values = array()) { if (!$table) return false; $metadata = $this->db->metadata($table); if (!is_array($metadata)) return false; $k=1; while ($k < count($metadata)) { $db_name = $metadata[$k]['name']; $k++; $web_name = $this->tables[$table]['fields'][$db_name]['name']; $value = $values[$db_name]; $checkType = $this->tables[$table]['fields'][$db_name]['checkType']; $mustExist = $this->tables[$table]['fields'][$db_name]['mustExist']; if ($web_name) { $name_print=$web_name; } else { $name_print=$db_name; } if ($mustExist) { if (!strlen($value)) { printf("Error: field '%s' must be filled in\n", $name_print); return false; } } if ($checkType) { if (!strlen($value)) { if (!$mustExist) continue; } if ($checkType == 'sip_account') { if (!checkEmail($value)) { printf( "Error: value '%s' for field '%s' must be of format 'user@domain'\n", $value, $name_print ); return false; } } if ($checkType == 'domain') { if (stristr($value, "-.") || !preg_match("/^([a-zA-Z0-9][a-zA-Z0-9-]*\.)+[a-zA-Z]{2,}$/i", $value)) { printf( "Error: value '%s' for field '%s' must be of format 'example.com'\n", $value, $name_print ); return false; } } if ($checkType == 'ip') { if (!preg_match("/^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i", $value, $m)) { printf( "Error: value '%s' for field '%s' must be of format 'X.X.X.X'\n", $value, $name_print ); return false; } else { $i=1; while ($i<=4) { if ($m[$i] < 0 || $m[$i] > 255) { printf( "Error: value '%s' for field '%s' must be of a valid IP address\n", $value, $name_print ); return false; } $i++; } } } if ($checkType == 'numeric') { if (!is_numeric($value)) { printf( "Error: value '%s' for field '%s' must be of type '%s'\n", $value, $name_print, $checkType ); return false; } } } } return true; } public function importTable($table = '') { // import a table from web if (!is_array($_FILES[$table]) || $_FILES[$table]['size'] == 0) return false; foreach ($this->importFilesPatterns as $_pattern) { if (strstr($_FILES[$table]['name'], $_pattern) && preg_match("/\.csv$/", $_FILES[$table]['name'])) { if ($this->CDRTool['filters']['reseller']) { $dir=$this->cvs_import_dir.'/'.$this->CDRTool['filters']['reseller']; if (!is_dir($dir)) { if (!mkdir($dir)) { printf("Error: cannot create directory %s", $dir); return false; } } $fullPath=$this->cvs_import_dir.'/'.$this->CDRTool['filters']['reseller'].'/'.$_FILES[$table]['name']; } else { $fullPath=$this->cvs_import_dir.'/'.$_FILES[$table]['name']; } if (!is_file($fullPath)) { if ($fp = fopen($fullPath, "w")) { } else { printf("Error: cannot open file %s for writing", $fullPath); return false; } } else { list($basename, $extension) = explode('.', $_FILES[$table]['name']); $j=0; while (1) { $j++; if ($this->CDRTool['filters']['reseller']) { $fullPath=$this->cvs_import_dir.'/'.$this->CDRTool['filters']['reseller'].'/'.$basename.'-'.$j.'.'.$extension; } else { $fullPath=$this->cvs_import_dir.'/'.$basename.'-'.$j.'.'.$extension; } if (is_file($fullPath)) continue; if ($fp = fopen($fullPath, "w")) { break; } else { printf("Error: cannot open file %s for writing", $fullPath); return false; } } } $content = fread( fopen($_FILES[$table]['tmp_name'], "r"), $_FILES[$table]['size'] ); fwrite($fp, $content); fclose($fp); printf( "

Imported %s bytes into %s", $_FILES[$table]['size'], $fullPath ); break; } } } } class OpenSIPSQuota { var $localDomains = array(); var $quotaGroup = 'quota'; // group set if subscriber was blocked by quota var $timeout = 5; // soap connection timeout var $daily_quota = 0; // by default do not check daily quota public function OpenSIPSQuota($parent) { global $DATASOURCES; $this->CDRdb = $parent->CDRdb; $this->table = $parent->table; $this->CDRTool = $parent->CDRTool; $this->cdr_source = $parent->cdr_source; $this->path=$this->CDRTool['Path']; $this->db_subscribers = $parent->db_subscribers; if (!class_exists($this->db_subscribers)) { printf("Info: No database defined for SIP accounts for source '%s'.\n", $this->cdr_source); return false; } $this->AccountsDB = new $this->db_subscribers; $this->enableThor = $parent->enableThor; $parent->LoadDomains(); $this->localDomains = $parent->localDomains; $this->cdr_source = $parent->cdr_source; $this->BillingPartyIdField = $parent->CDRFields['BillingPartyId']; $this->parent = $parent; $this->db = new DB_cdrtool; $this->db->Halt_On_Error="no"; $this->db1 = new DB_cdrtool; $this->db1->Halt_On_Error="no"; $this->db1 = new DB_cdrtool; $this->db1->Halt_On_Error="no"; $this->CDRS = $parent; $this->quota_init_flag = $parent->quota_init_flag; $this->quota_reset_flag = $parent->quota_reset_flag; if ($parent->daily_quota && is_numeric($parent->daily_quota) && $parent->daily_quota > 1 && $parent->daily_quota < 100) { $this->daily_quota = $parent->daily_quota; } // load e-mail addresses for quota notifications $query = "select * from settings where var_module = 'notifications'"; if ($this->db->query($query) && $this->db->num_rows()) { while ($this->db->next_record()) { $_bp = $this->db->f('billing_party'); $_name = $this->db->f('var_name'); $_value = $this->db->f('var_value'); if ($_bp && $_name && $_value) { $this->notificationAddresses[$_bp][$_name]=$_value; } } } if ($DATASOURCES[$this->cdr_source]['soapEngineId']) { require("/etc/cdrtool/ngnpro_engines.inc"); require_once("ngnpro_soap_library.php"); if (in_array($DATASOURCES[$this->cdr_source]['soapEngineId'], array_keys($soapEngines))) { $this->SOAPurl = $soapEngines[$DATASOURCES[$this->cdr_source]['soapEngineId']]['url']; $log = sprintf( "Using SOAP engine %s to block accounts at %s\n", $DATASOURCES[$this->cdr_source]['soapEngineId'], $this->SOAPurl ); syslog(LOG_NOTICE, $log); $this->SOAPlogin = array( "username" => $soapEngines[$DATASOURCES[$this->cdr_source]['soapEngineId']]['username'], "password" => $soapEngines[$DATASOURCES[$this->cdr_source]['soapEngineId']]['password'], "admin" => true ); $this->SoapAuth=array('auth', $this->SOAPlogin , 'urn:AGProjects:NGNPro', 0, ''); $this->soapclient = new WebService_NGNPro_SipPort($this->SOAPurl); $this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0); $this->soapclient->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0); $this->soapclient->_options['timeout'] = $this->timeout; } else { $e = $DATASOURCES[$this->cdr_source]['soapEngineId']; $log = "Error: soap engine id $e not found in /etc/cdrtool/ngnpro_engines.inc\n"; print $log; syslog(LOG_NOTICE, $log); return false; } } else { $log = "Using database queries to block accounts\n"; syslog(LOG_NOTICE, $log); } } function ShowAccountsWithQuota($treshhold = '') { $query = sprintf( "select * from quota_usage where datasource = '%s' and quota > 0 and cost > 0", addslashes($this->CDRS->cdr_source) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } while ($this->db->next_record()) { if ($this->db->f('blocked')) { $blockedStatus="blocked"; } else { $blockedStatus=''; } $usageRatio = $this->db->f('cost') * 100 / $this->db->f('quota'); if ($treshhold && $treshhold > $usageRatio) continue; $usageStatus = sprintf("usage=%-10s", $this->db->f('cost')); printf( "%-35s quota=%-6s %s %.2f%s %s\n", $this->db->f('account'), $this->db->f('quota'), $usageStatus, $usageRatio, '%', $blockedStatus ); } } public function deblockAccounts($reset_quota_for = array()) { // deblock users blocked by quota if (!$this->db_subscribers) { print("Info: No database defined for SIP accounts.\n"); return false; } if (!count($reset_quota_for)) { printf("Deblocking all SIP accounts blocked by quota\n"); } else { printf("Deblocking %d SIP accounts blocked by quota\n", count($reset_quota_for)); } if ($this->enableThor) { $query = sprintf("select username, domain, profile from sip_accounts where (1=1) "); if (count($reset_quota_for)) { $k=0; foreach ($reset_quota_for as $_account) { if ($k) $usage_keys.= ", "; $usage_keys.="'".addslashes($_account)."'"; $k++; } $query.= "and CONCAT(username,'@',domain) in (".$usage_keys.")"; } if (!$this->AccountsDB->query($query)) { $log = sprintf("Error: %s (%s)", $this->AccountsDB->Error, $this->AccountsDB->Errno); syslog(LOG_NOTICE, $log); return false; } while ($this->AccountsDB->next_record()) { $i++; $_account=$this->AccountsDB->f('username')."@".$this->AccountsDB->f('domain'); $_profile=json_decode(trim($this->AccountsDB->f('profile'))); if (in_array('quota', $_profile->groups)) { $blockedAccounts[]=$_account; } if ($i%5000 == 0) { print "$i accounts checked for deblocking\n"; flush(); } } if ($i) { print "$i accounts checked for deblocking\n"; flush(); } } else { $query = sprintf( "select CONCAT(username,'@',domain) as account from grp where grp = '%s'", addslashes($this->quotaGroup) ); if (count($reset_quota_for)) { $k=0; foreach ($reset_quota_for as $_account) { if ($k) $usage_keys.= ", "; $usage_keys .= "'".addslashes($_account)."'"; $k++; } $query.= "and CONCAT(username,'@',domain) in (".$usage_keys.")"; } if (!$this->AccountsDB->query($query)) { $log = sprintf( "Database error: %s (%s)", $this->AccountsDB->Error, $this->AccountsDB->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $blockedAccounts=array(); while ($this->AccountsDB->next_record()) { $i++; $blockedAccounts[]=$this->AccountsDB->f('account'); if ($i%10000 == 0) { print "$i accounts checked for deblocking\n"; flush(); } } } if (count($reset_quota_for)) { $blockedAccounts = array_intersect($blockedAccounts, $reset_quota_for); } if (count($blockedAccounts) >0) { $this->unBlockRemoteAccounts($blockedAccounts); if (!$this->enableThor) { $query = sprintf("delete from grp where grp = '%s'", $this->quotaGroup); if (count($reset_quota_for)) { $k=0; foreach ($reset_quota_for as $_account) { if ($k) $usage_keys.= ", "; $usage_keys.="'".addslashes($_account)."'"; $k++; } $query.= "and CONCAT(username,'@',domain) in (".$usage_keys.")"; } if (!$this->AccountsDB->query($query)) { $log = sprintf( "Database error: %s (%s)", $this->AccountsDB->Error, $this->AccountsDB->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } } } if (count($blockedAccounts)) { $log = sprintf( "Reset %d users blocked by quota\n", count($blockedAccounts) ); print $log; syslog(LOG_NOTICE, $log); } } private function initQuotaUsageFromDatabase($month = "", $reset_quota_for = array()) { if (!$month) { $this->startTime=Date("Y-m-01 00:00", time()); } else { $this->startTime=$month."-01 00:00"; } $j=0; $usage_keys=''; if (count($reset_quota_for)) { $log = sprintf( "Init quota of data source %s for %d accounts\n", addslashes($this->CDRS->cdr_source), count($reset_quota_for) ); print $log; syslog(LOG_NOTICE, $log); $k=0; foreach ($reset_quota_for as $_account) { if ($k) $usage_keys.= ", "; $usage_keys.="'".addslashes($_account)."'"; $k++; } $usage_keys="and ".addslashes($this->BillingPartyIdField). " in (".$usage_keys.")"; } else { if (count($this->localDomains)) { $domain_filter="and Realm in ("; $t=0; foreach (array_keys($this->localDomains) as $_domain) { if (!$_domain) continue; if ($t) $domain_filter .= ","; $domain_filter .= sprintf("'%s'", addslashes($_domain)); $t++; } $domain_filter .= ") "; } $log = sprintf( "Init quota of data source %s for all accounts\n", $this->CDRS->cdr_source ); print $log; syslog(LOG_NOTICE, $log); } $query = sprintf( "select %s, count(*) as calls, sum(AcctSessionTime) as duration, sum(Price) as cost, sum(AcctInputOctets + AcctOutputOctets)/2 as traffic from %s where AcctStartTime >= '%s' and Normalized = '1' %s %s group by %s\n", addslashes($this->BillingPartyIdField), addslashes($this->table), addslashes($this->startTime), $domain_filter, $usage_keys, addslashes($this->BillingPartyIdField) ); if (!$this->CDRdb->query($query)) { if ($this->CDRdb->Errno != 1146) { $log = sprintf( "Database error: %s (%s)", $this->CDRdb->Error, $this->CDRdb->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } } $rows = $this->CDRdb->num_rows(); $log = sprintf( "%d callers generated traffic in %s for data source %s\n", $rows, Date("Y-m", time()), $this->CDRS->cdr_source ); print $log; flush(); syslog(LOG_NOTICE, $log); $j=0; $progress=0; while ($this->CDRdb->next_record()) { if ($rows > 1000) { if ($j > $progress * $rows/100) { $progress++; if ($progress % 10 == 0) { print "$progress% "; flush(); } } } unset($accounts); $accounts[$this->CDRdb->f($this->BillingPartyIdField)]['usage']['calls'] = $this->CDRdb->f('calls'); $accounts[$this->CDRdb->f($this->BillingPartyIdField)]['usage']['duration'] = $this->CDRdb->f('duration'); $accounts[$this->CDRdb->f($this->BillingPartyIdField)]['usage']['cost'] = $this->CDRdb->f('cost'); $accounts[$this->CDRdb->f($this->BillingPartyIdField)]['usage']['traffic'] = $this->CDRdb->f('traffic'); $accounts[$this->CDRdb->f($this->BillingPartyIdField)]['usage']['cost_today'] = 0; $this->CDRS->cacheQuotaUsage($accounts); $j++; } } public function checkQuota($notify) { global $UserQuota; $this->initQuotaUsage(); $query = sprintf( "select * from quota_usage where datasource = '%s' and quota > 0 and (cost > quota or cost_today >= quota * $this->daily_quota/100)", addslashes($this->CDRS->cdr_source) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $toNotify=array(); $_checks=0; while ($this->db->next_record()) { $account=$this->db->f('account'); list($username, $domain)=explode("@", $account); if ($this->db->f('cost') >= $this->db->f('quota')) { $quota_exceeded = true; $exceeded_period = 'monthly'; } elseif ($this->daily_quota && ($this->db->f('cost_today') >= $this->db->f('quota') * $this->daily_quota/100)) { $quota_exceeded = true; $exceeded_period = 'daily'; } else { $quota_exceeded = false; } if ($quota_exceeded) { $exceeding_accounts++; if (!$this->db->f('blocked')) { $reason='Cost exceeded'; if (!$seen_title) { $line = sprintf( "%40s %6s %8s %8s %13s %s\n", "User", "Calls", "Price", "Minutes", "Traffic", "Reason" ); print $line; $email_body=$line; $seen_title++; } $line = sprintf( "%40s %6s %8s %8s %10s MB %s\n", $account, $this->db->f('calls'), $this->db->f('cost'), number_format($this->db->f('duration') / 60, 0, "", ""), number_format($this->db->f('traffic') / 1024 / 1024, 2), $reason ); $email_body = $email_body.$line; print $line; if ($this->enableThor) { $this->domain_table = "sip_domains"; } else { $this->domain_table = "domain"; } $query = sprintf( "select * from %s where domain = '%s'", addslashes($this->domain_table), addslashes($domain) ); if (!$this->AccountsDB->query($query)) { $log = sprintf( "Database error: %s (%d) %s\n", $this->AccountsDB->Error, $this->AccountsDB->Errno, $query ); syslog(LOG_NOTICE, $log); } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); $_reseller = $this->AccountsDB->f('reseller_id'); } else { $_reseller = 0; } $log = sprintf( "%s quota exceeded for %s (%s > %s)", ucfirst($exceeded_period), $account, $this->db->f('cost'), $this->db->f('quota') ); syslog(LOG_NOTICE, $log); $log_query = sprintf( "insert into log (date,login,ip,datasource,results,description,reseller_id) values (NOW(),'quotacheck','localhost','QuotaCheck','1','%s',%d)", addslashes($log), $_reseller ); if (!$this->db1->query($log_query)) { $log = sprintf( "Database error: %s (%s)", $this->db1->Error, $this->db1->Errno ); print $log; syslog(LOG_NOTICE, $log); } if ($this->blockAccount($account)) { if ($notify) { $toNotify[]=$account; } $blocked_now++; $blockedAccountsNow=$blockedAccountsNow.$account."\n"; } } else { $blockedAccountsPrevious=$blockedAccountsPrevious.$account."\n"; $blocked_previous++; } } $_checks++; } if ($exceeding_accounts) { $line = sprintf("%6d accounts have exceeded their traffic limits\n", $exceeding_accounts); print $line; $email_body=$email_body.$line; } else { $log=sprintf("No quota has been exceeded\n"); syslog(LOG_NOTICE, $log); } if ($blocked_now) { $line = sprintf("%6d accounts have been blocked now\n", $blocked_now); $email_body=$email_body.$line; } if ($blockedAccountsNow) { $line = "Blocked accounts now:\n".$blockedAccountsNow; print $line; $email_body=$email_body.$line.$batch_block; } if ($blockedAccountsPrevious) { $line = "Blocked acccounts previously:\n".$blockedAccountsPrevious; print $line; $email_body=$email_body.$line.$batch_unblock; } // send notification to the provider if ($this->CDRTool['provider']['toEmail'] && $blockedAccountsNow) { $from = $this->CDRTool['provider']['fromEmail']; $to = $this->CDRTool['provider']['toEmail']; $bcc = $this->CDRTool['provider']['bccEmail']; $service = $this->CDRTool['provider']['service']; if (!$service) $service = "SIP"; if ($from) $extraHeaders="From: $from\r\nBCC: $from"; if ($bcc) $extraHeaders=$extraHeaders.",".$bcc; print("Notify CDRTool provider at $to\n"); mail($to, "$service platform - CDRTool quota check", $email_body, $extraHeaders); } if ($notify && is_array($toNotify) && count($toNotify) >0) { // send notification to accounts foreach ($toNotify as $rcpt) { $this->notify($rcpt); } } } function notify($account) { global $DATASOURCES; list($username, $domain) = explode("@", $account); if (!$DATASOURCES[$this->cdr_source]['UserQuotaNotify']) { return false; } // get account information if ($this->enableThor) { $query = sprintf( "select first_name,last_name,email,profile from sip_accounts where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain) ); } else { $query = sprintf( "select first_name,last_name,email_address as email,profile from subscriber where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain) ); } if (!$this->AccountsDB->query($query)) { $log = sprintf( "Database error: %s (%s)", $this->AccountsDB->Error, $this->AccountsDB->Errno ); syslog(LOG_NOTICE, $log); return false; } if (!$this->AccountsDB->num_rows()) return false; $this->AccountsDB->next_record(); $fullname = $this->AccountsDB->f('first_name')." ".$this->AccountsDB->f('last_name'); $toEmail = $this->AccountsDB->f('email'); $profile = json_decode($this->AccountsDB->f('profile'), true); $providerName=$this->notificationAddresses[$domain]['providerName']; if (!$providerName) $providerName="your SIP service provider"; $body = sprintf( "Dear __NAME__,\n\n". "Your SIP account %s has been temporarily blocked\n". "because your monthly quota has been exceeded.\n\n". "To unblock your account you may contact %s.\n\n". "N.B. This is an automatically generated message. Do not reply to it.\n", $account, $providerName ); $fromEmail = $this->CDRTool['provider']['fromEmail']; $bccEmail = $this->CDRTool['provider']['bccEmail']; $seen_bcc[$bccEmail]++; if ($this->notificationAddresses[$domain]['fromEmail']) { $fromEmail=$this->notificationAddresses[$domain]['fromEmail']; } if ($this->notificationAddresses[$domain]['quotaBody']) { $body=$this->notificationAddresses[$domain]['quotaBody']; } if ($this->notificationAddresses[$domain]['quotaSubject']) { $subject=$this->notificationAddresses[$domain]['quotaSubject']; } $body = preg_replace("/__NAME__/", $fullname, $body); $body = preg_replace("/__ACCOUNT__/", $account, $body); $body = preg_replace("/__CALLERID__/", "$profile[rpid]", $body); if (!$subject) { $subject=sprintf("Monthly quota exceeded for account %s", $account); } else { $subject=preg_replace("/__ACCOUNT__/", $account, $subject); $subject=preg_replace("/__CALLERID__/", "$profile[rpid]", $subject); } if (!$toEmail || !$fromEmail) { return false; } $seen_bcc[$toEmail]++; $extraHeaders="From: $fromEmail"; if ($this->notificationAddresses[$domain][bccEmail]) { if ($bccEmail) $bccEmail.= ","; $bccEmail.=$this->notificationAddresses[$domain][bccEmail]; } if ($bccEmail) $extraHeaders = $extraHeaders."\r\nBCC: ".$bccEmail; mail($toEmail, $subject, $body, $extraHeaders); $log_msg = sprintf( "Monthly quota exceeded for %s. Notified To:%s From:%s\n", $account, $toEmail, $fromEmail ); syslog(LOG_NOTICE, $log_msg); print $log_msg; } function blockAccount($account) { list($username, $domain) = explode("@", $account); if (is_object($this->soapclient)) { return $this->blockAccountRemote($account); } else { $query = sprintf( "insert into grp (username,domain,grp,last_modified) values ('%s','%s','%s',NOW())", addslashes($username), addslashes($domain), addslashes($this->quotaGroup) ); if (!$this->AccountsDB->query($query)) { if ($this->AccountsDB->Errno != 1062) { $log = sprintf( "Database error: %s (%s)", $this->AccountsDB->Error, $this->AccountsDB->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } else { return true; } } else { $this->markBlocked($account); return true; } } } function blockAccountRemote($account) { list($username, $domain) = explode("@", $account); if (!$username || !$domain) { $log = sprintf("Error: misssing username/domain in blockAccountRemote()"); syslog(LOG_NOTICE, $log); return false; } $this->soapclient->addHeader($this->SoapAuth); $result = $this->soapclient->addToGroup(array("username" => $username,"domain"=> $domain), "quota"); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault = $result->getFault(); $error_code = $result->getCode(); $log = sprintf( "Error from %s: %s (%s)", $this->SOAPurl, $error_fault->faultstring, $error_fault->faultcode ); syslog(LOG_NOTICE, $log); print $log; if ($error_fault->detail->exception->errorcode != "1030") { $from = $this->CDRTool['provider']['fromEmail']; $to = $this->CDRTool['provider']['toEmail']; $extraHeaders = "From: $from"; $email_body = "Remote SOAP request failure when calling blockAccountRemote(): \n\n". $log; mail($to, "CDRTool SOAP client failure", $email_body, $extraHeaders); } return false; } else { $log = sprintf("Block account %s at %s", $account, $this->SOAPurl); syslog(LOG_NOTICE, $log); $this->markBlocked($account); return true; } } function unBlockRemoteAccounts($accounts) { if (!is_object($this->soapclient)) { return; } foreach ($accounts as $account) { list($username, $domain)=explode("@", $account); if (!$username || !$domain) return true; $this->soapclient->addHeader($this->SoapAuth); $result = $this->soapclient->removeFromGroup(array("username" => $username,"domain"=> $domain), "quota"); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault = $result->getFault(); $error_code = $result->getCode(); if ($error_fault->detail->exception->errorcode && $error_fault->detail->exception->errorcode != "1030" && $error_fault->detail->exception->errorcode != "1031" ) { $from = $this->CDRTool[provider][fromEmail]; $to = $this->CDRTool[provider][toEmail]; $extraHeaders="From: $from"; $email_body="SOAP request failure: \n\n". $log = sprintf( "SOAP client error: %s %s\n", $error_fault->detail->exception->errorcode, $error_fault->detail->exception->errorstring ); syslog(LOG_NOTICE, $log); mail($to, "CDRTool SOAP failure", $email_body, $extraHeaders); } } else { $log = sprintf("Unblock remote account %s at %s", $account, $this->SOAPurl); syslog(LOG_NOTICE, $log); } } } function saveQuotaInitFlag() { $query = sprintf("insert into memcache (`key`,`value`) values ('%s','1')", addslashes($this->quota_init_flag)); if (!$this->db->query($query)) { if ($this->db->Errno != '1062') { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } } return true; } function deleteQuotaInitFlag() { $query = sprintf( "delete from memcache where `key` in ('%s','%s')", addslashes($this->quota_init_flag), addslashes($this->quota_reset_flag) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } return true; } function deleteQuotaUsageFromCache ($reset_quota_for=array()) { $query = sprintf( "delete from quota_usage where datasource = '%s' ", addslashes($this->CDRS->cdr_source) ); if (count($reset_quota_for)) { $query.= " and account in ("; $t=0; foreach ($reset_quota_for as $_account) { if ($t) $query.=","; $query.= sprintf("'%s'", $_account); $t++; } $query.=")"; } if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->affected_rows()) { $log = sprintf("Deleted %d keys from cache\n", $this->db->affected_rows()); print $log; syslog(LOG_NOTICE, $log); } return true; } private function initQuotaUsage() { $query = sprintf( "select value from memcache where `key` = '%s'", addslashes($this->quota_init_flag) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } if ($this->db->num_rows()) return true; $lockName = sprintf("%s:%s", $this->CDRS->cdr_source, $this->CDRS->table); if (!$this->CDRS->getNormalizeLock($lockName)) { $log = "Error: cannot initialize now the quota because a normalization process in progress\n"; print $log; syslog(LOG_NOTICE, $log); return false; } $query = sprintf( "select value from memcache where `key` = '%s'", addslashes($this->quota_reset_flag) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } $reset_quota_for= array(); if ($this->db->num_rows()) { $this->db->next_record(); $reset_quota_for = json_decode($this->db->f('value')); } $this->deblockAccounts($reset_quota_for); $this->deleteQuotaUsageFromCache($reset_quota_for); $this->initQuotaUsageFromDatabase('', $reset_quota_for); if ($this->CDRS->status['cached_keys']['saved_keys']) { $log = sprintf( "Saved %d accounts in quota cache\n", $this->CDRS->status['cached_keys']['saved_keys'] ); print $log; syslog(LOG_NOTICE, $log); } if ($this->CDRS->status['cached_keys']['failed_keys']) { $log = sprintf( "Error: failed to save %d account\n", $this->CDRS->status['cached_keys']['failed_keys'] ); print $log; syslog(LOG_NOTICE, $log); } if ($this->saveQuotaInitFlag()) { $query = sprintf( "delete from memcache where `key` = '%s'", addslashes($this->quota_reset_flag) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } return true; } else { $log = "Error: failed to save key quotaCheckInit"; syslog(LOG_NOTICE, $log); return false; } } function markBlocked($account) { $query = sprintf( "update quota_usage set blocked = '1', notified = NOW() where account = '%s' and datasource = '%s'", addslashes($account), addslashes($this->CDRS->cdr_source) ); if (!$this->db1->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db1->Error, $this->db1->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } } function resetDailyQuota() { $query = sprintf( "update quota_usage set cost_today = 0 where datasource = '%s'", addslashes($this->CDRS->cdr_source) ); if (!$this->db1->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->db1->Error, $this->db1->Errno ); print $log; syslog(LOG_NOTICE, $log); return false; } return true; } } class RatingEngine { var $method = ''; var $log_runtime = false; var $prepaid_table = "prepaid"; var $init_ok = false; public function RatingEngine() { global $RatingEngine; // set in global.inc global $DATASOURCES; // set in global.inc if (!strlen($RatingEngine['socketIP']) || !$RatingEngine['socketPort'] || !$RatingEngine['cdr_source']) { $log = sprintf("Please define \$RatingEngine['socketIP'], \$RatingEngine['socketPort'] and \$RatingEngine['cdr_source'] in /etc/cdrtool/global.inc\n"); syslog(LOG_NOTICE, $log); return false; } if (preg_match("/^\d{1-3}\.\d{1-3}\.\d{1-3}\.\d{1-3}$/", $RatingEngine['socketIP'])) { $log = sprintf("Invalid \$RatingEngine['socketIP'] in /etc/cdrtool/global.inc\n"); syslog(LOG_NOTICE, $log); return false; } if (intval($RatingEngine['socketPort']) < 1 || intval($RatingEngine['socketPort']) > 65535) { $log = sprintf("Invalid \$RatingEngine['socketPort'] in /etc/cdrtool/global.inc\n"); syslog(LOG_NOTICE, $log); return false; } if (!is_array($DATASOURCES[$RatingEngine['cdr_source']])) { $log = sprintf("Datasource '%s' does not exist in /etc/cdrtool/global.inc\n", $RatingEngine['cdr_source']); syslog(LOG_NOTICE, $log); return false; } $this->settings = $RatingEngine; if ($this->settings['log_runtime']) { $this->log_runtime=true; } // init database $this->db = new DB_CDRTool; $query=sprintf("delete from memcache where `key` = 'destinations_sip' or `key` = 'destinations'"); if (!$this->db->query($query)) { $log = sprintf( "Database error: %s (%s) for query %s", $db->Error, $db->Errno, $query ); syslog(LOG_NOTICE, $log); } // init CDR datasource $CDR_class = $DATASOURCES[$RatingEngine['cdr_source']]['class']; $this->CDRS = new $CDR_class($RatingEngine['cdr_source']); // load Rating Tables $this->CDRS->RatingTables = new RatingTables(); $this->CDRS->RatingTables->LoadRatingTables(); // init subscribers database $this->db_subscribers_class = $this->CDRS->db_subscribers; if (!class_exists($this->db_subscribers_class)) { syslog(LOG_NOTICE, "Error: No database defined for SIP accounts"); return false; } $this->AccountsDB = new $this->db_subscribers_class; $this->enableThor = $this->CDRS->enableThor; $this->init_ok = true; } function reloadRatingTables() { $b=time(); //$query="delete from memcache where `key` in ('destinations','destinations_sip','ENUMtlds')"; $query = "delete from memcache where `key` in ('ENUMtlds')"; if (!$this->db->query($query)) { $log = sprintf( "Database error: %s (%s)", $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE,$log); } $this->CDRS->RatingTables->LoadRatingTables(); $e=time(); $d=$e-$b; if ($d > 0 ) syslog(LOG_NOTICE, "Reloaded rating tables in $d seconds"); $b=time(); $this->CDRS->LoadDestinations(); $e=time(); $d=$e-$b; if ($d > 0 ) syslog(LOG_NOTICE, "Reloaded destinations in $d seconds"); $this->db->query("update settings set var_value = '' where var_name = 'reloadRating'"); return 1; } function reloadCustomers($customerFilter) { return 1; } function reloadDomains() { return 1; } function reloadQuota($account) { if (!$account) return false; $quota = $this->getQuota($account); $blocked = $this->getBlockedByQuotaStatus($account); $query = sprintf( "update quota_usage set quota = '%s', blocked = '%s' where datasource = '%s' and account = '%s'", $quota, intval($blocked), $this->CDRS->cdr_source, addslashes($account) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query '%s': %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return 0; } return 1; } function getBalanceHistory($account, $limit = 50) { list($username, $domain)=explode("@", $account); if (!$username || !$domain) return 0; $query = sprintf( "select * from prepaid_history where username = '%s' and domain = '%s' order by id desc", addslashes($username), addslashes($domain) ); if ($limit) $query.= sprintf(" limit %d", $limit); if (!$this->db->query($query)) { $log = sprintf( "getBalanceHistory error: %s (%s)", $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return 0; } while ($this->db->next_record()) { $history[] = array( 'account' => $account, 'action' => $this->db->f('action'), 'description' => $this->db->f('description'), 'value' => $this->db->f('value'), 'balance' => $this->db->f('balance') ); } $line = json_encode($history); return $line; } function DebitBalanceAudio($account, $balance, $session_id, $duration, $force = false) { $this->old_session_count = 0; $this->new_session_count = 0; $els = explode(":", $account); if (count($els) == 2) { $account=$els[1]; } if (!$account) { syslog(LOG_NOTICE, "DebitBalanceAudio() error: missing account"); return 0; } if (!is_numeric($balance)) { syslog(LOG_NOTICE, "DebitBalanceAudio() error: balance must be numeric"); return 0; } if (!$session_id) { syslog(LOG_NOTICE, "DebitBalanceAudio() error: missing call id"); return 0; } $query = sprintf( "select * from %s where account = '%s'", addslashes($this->prepaid_table), addslashes($account) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); $this->logRuntime(); return 0; } if (!$this->db->num_rows()) { $log = sprintf("DebitBalanceAudio() error: account %s does not exist", $account); syslog(LOG_NOTICE, $log); $this->logRuntime(); return 0; } $this->db->next_record(); if (strlen($this->db->f('active_sessions'))) { // remove active session $active_sessions = array(); $old_active_sessions = json_decode($this->db->f('active_sessions'), true); $destination=$old_active_sessions[$session_id]['Destination']; if (!$force) { if (!in_array($session_id, array_keys($old_active_sessions))) { $this->sessionDoesNotExist=true; $log = sprintf( "Error: session %s of %s does not exist", $session_id, $account ); syslog(LOG_NOTICE, $log); return 0; } } foreach (array_keys($old_active_sessions) as $_key) { if ($_key==$session_id) continue; $active_sessions[$_key]=$old_active_sessions[$_key]; } } else { if (!$force) { $this->sessionDoesNotExist=true; $log = sprintf( "Error: session %s for %s does not exist", $session_id, $account ); syslog(LOG_NOTICE, $log); return 0; } } $next_balance = $this->db->f('balance') - $balance; //get parallel calls and remaining_balance $this->getActivePrepaidSessions($active_sessions, $next_balance, $account); // calculate the updated maxsessiontime $maxsessiontime = $this->getAggregatedMaxSessiontime( $this->parallel_calls, $this->remaining_balance, $account ); $this->old_session_count = count($old_active_sessions); $this->new_session_count = count($active_sessions); $query = sprintf( "update %s set balance = balance - '%s', change_date = NOW(), active_sessions = '%s', session_counter = '%s' where account = '%s'", addslashes($this->prepaid_table), addslashes($balance), addslashes(json_encode($active_sessions)), count($active_sessions), addslashes($account) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return 0; } if ($balance > 0) { list($prepaidUser, $prepaidDomain)=explode("@", $account); if ($this->enableThor) { $this->domain_table = "sip_domains"; } else { $this->domain_table = "domain"; } $query = sprintf( "select * from %s where domain = '%s'", addslashes($this->domain_table), addslashes($prepaidDomain) ); if (!$this->AccountsDB->query($query)) { $log = sprintf( "Database error: %s (%d) %s\n", $this->AccountsDB->Error, $this->AccountsDB->Errno, $query ); syslog(LOG_NOTICE, $log); } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); $_reseller=$this->AccountsDB->f('reseller_id'); } else { $_reseller=0; } $query = sprintf( "insert into prepaid_history (username,domain,action,description,value,balance,date,session,duration,destination,reseller_id) values ('%s','%s','Debit balance','Session to %s for %ds','-%s','%s',NOW(),'%s','%d','%s',%d)", addslashes($prepaidUser), addslashes($prepaidDomain), addslashes($destination), addslashes($duration), addslashes($balance), addslashes($next_balance), addslashes($session_id), addslashes($duration), addslashes($destination), addslashes($_reseller) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); } } return $maxsessiontime; } function DebitBalanceMessage($account, $destination, $balance, $session_id) { $els = explode(":", $account); if (count($els) == 2) { $account=$els[1]; } if (!$account) { syslog(LOG_NOTICE, "DebitBalanceMessage() error: missing account"); return 0; } if (!is_numeric($balance)) { syslog(LOG_NOTICE, "DebitBalanceMessage() error: balance must be numeric"); return 0; } if (!$session_id) { syslog(LOG_NOTICE, "DebitBalanceMessage() error: missing call id"); return 0; } $query = sprintf( "select * from %s where account = '%s'", addslashes($this->prepaid_table), addslashes($account) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); $this->logRuntime(); return 0; } if (!$this->db->num_rows()) { $log = sprintf("DebitBalanceMessage() error: account %s does not exist", $account); syslog(LOG_NOTICE, $log); $this->logRuntime(); return 0; } $this->db->next_record(); if (strlen($this->db->f('active_sessions'))) { $active_sessions = json_decode($this->db->f('active_sessions'), true); } $next_balance=$this->db->f('balance')-$balance; //get parallel calls and remaining_balance $this->getActivePrepaidSessions($active_sessions, $next_balance, $account); // calculate the updated maxsessiontime $maxsessiontime = $this->getAggregatedMaxSessiontime( $this->parallel_calls, $this->remaining_balance, $account ); $query = sprintf( "update %s set balance = balance - '%s', change_date = NOW() where account = '%s'", addslashes($this->prepaid_table), addslashes($balance), addslashes($account) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return 0; } if ($balance > 0) { list($prepaidUser, $prepaidDomain) = explode("@", $account); if ($this->enableThor) { $this->domain_table = "sip_domains"; } else { $this->domain_table = "domain"; } $query = sprintf( "select * from %s where domain = '%s'", addslashes($this->domain_table), addslashes($prepaidDomain) ); if (!$this->AccountsDB->query($query)) { $log = sprintf( "Database error: %s (%d) %s\n", $this->AccountsDB->Error, $this->AccountsDB->Errno, $query ); syslog(LOG_NOTICE, $log); } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); $_reseller=$this->AccountsDB->f('reseller_id'); } else { $_reseller=0; } $query = sprintf( "insert into prepaid_history (username,domain,action,description,value,balance,date,session,destination,reseller_id) values ('%s','%s','Debit balance','Message to %s','-%s','%s',NOW(),'%s','%s',%d)", addslashes($prepaidUser), addslashes($prepaidDomain), addslashes($destination), addslashes($balance), addslashes($next_balance), addslashes($session_id), addslashes($destination), addslashes($_reseller) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); } } return true; } function CreditBalance($account, $balance) { if (!is_numeric($balance)) { syslog(LOG_NOTICE, "CreditBalance() error: balance \"$balance\"is invalid"); return 0; } $els = explode(":", $account); if (count($els) == 2) { $account=$els[1]; } if (!$account) { syslog(LOG_NOTICE, "CreditBalance() error: missing account"); return 0; } list($prepaidUser, $prepaidDomain) = explode("@", $account); $query = sprintf( "select * from %s where account = '%s'", addslashes($this->prepaid_table), addslashes($account) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); $this->logRuntime(); return 0; } if ($this->db->num_rows()) { $this->db->next_record(); $current_balance = $this->db->f('balance'); $query = sprintf( "update %s set balance = balance + '%s', change_date = NOW() where account = '%s'", addslashes($this->prepaid_table), addslashes($balance), addslashes($account) ); $this->db->query($query); if ($this->db->affected_rows()) { $new_balance = $current_balance + $balance; $log = sprintf("Prepaid account %s credited with %s", $account, $balance); syslog(LOG_NOTICE, $log); // log to prepaid_history $query = sprintf( "insert into prepaid_history (username,domain,action,description,value,balance,date) values ('%s','%s','Set balance','Manual update','%s','%s',NOW())", addslashes($prepaidUser), addslashes($prepaidDomain), addslashes($balance), addslashes($new_balance) ); if (!$this->db->query($query)) { $log = sprintf("Error: %s (%s)", $this->db->Error, $this->db->Errno); syslog(LOG_NOTICE, $log); } return 1; } else { $log = sprintf( "CreditBalance() error: failed to credit balance: %s (%s)", $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return 0; } } else { $query = sprintf( "insert into %s (balance, account, change_date) values ('%s','%s',NOW())", addslashes($this->prepaid_table), addslashes($balance), addslashes($account) ); $this->db->query($query); if ($this->db->affected_rows()) { $log = sprintf("Added prepaid account %s with balance=%s", $account, $balance); syslog(LOG_NOTICE, $log); // log to prepaid_history $query = sprintf( "insert into prepaid_history (username,domain,action,description,value,balance,date) values ('%s','%s','Set balance','Manual update','%s','%s',NOW())", addslashes($prepaidUser), addslashes($prepaidDomain), addslashes($balance), addslashes($balance) ); if (!$this->db->query($query)) { $log = sprintf("Error: %s (%s)", $this->db->Error, $this->db->Errno); syslog(LOG_NOTICE, $log); } return 1; } else { $log = sprintf( "CreditBalance() error: failed to credit balance: %s (%s)", $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return 0; } } } function DeleteBalance($account) { $els = explode(":", $account); if (count($els) == 2) { $account = $els[1]; } if (!$account) { syslog(LOG_NOTICE, "DeleteBalance() error: missing account"); return 0; } $query = sprintf( "delete from %s where account = '%s'", addslashes($this->prepaid_table), addslashes($account) ); if (!$this->db->query($query)) { $log = sprintf( "DeleteBalance error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return 0; } $log = sprintf("Prepaid account %s has been deleted", $account); syslog(LOG_NOTICE, $log); return 1; } function DeleteBalanceHistory($account) { $account=trim($account); $els = explode(":", $account); if (count($els) == 2) { $account=$els[1]; } if (!$account) { syslog(LOG_NOTICE, "DeleteBalanceHistory() error: missing account"); return 0; } list($username, $domain) = explode('@', $account); $query = sprintf( "delete from prepaid_history where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain) ); if (!$this->db->query($query)) { $log = sprintf( "DeleteBalanceHistory error for query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return 0; } $log = sprintf("History of prepaid account %s has been deleted", $account); syslog(LOG_NOTICE, $log); return 1; } function GetEntityProfiles($entity) { if (!$entity) { syslog(LOG_NOTICE, "GetEntityProfiles"); return 0; } $query = sprintf( "select * from billing_customers where subscriber = '%s' or domain = '%s' or gateway = '%s'", addslashes($entity), addslashes($entity), addslashes($entity) ); if (!$this->db->query($query)) { $log = sprintf( "GetEntityProfiles error: %s (%s)", $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return 0; } if ($this->db->num_rows() == 1) { $this->db->next_record(); $entity = array( 'entity' => $entity, 'profileWeekday' => $this->db->f('profile_name1'), 'profileWeekdayAlt' => $this->db->f('profile_name1_alt'), 'profileWeekend' => $this->db->f('profile_name2'), 'profileWeekendAlt' => $this->db->f('profile_name2_alt'), 'timezone' => $this->db->f('timezone'), 'increment' => $this->db->f('increment'), 'min_duration' => $this->db->f('min_duration') ); } $line = json_encode($entity); return $line; } function SetEntityProfiles($entity, $profiles) { if (!$entity) { syslog(LOG_NOTICE, "SetEntityProfiles"); return 0; } } function showHelp() { $help= "Version\n". "Help\n". "ShowClients\n". "MaxSessionTime CallId=6432622xvv@1 From=sip:123@example.com To=sip:0031650222333@example.com Duration=7200 Gateway=10.0.0.1 Lock=1\n". "ShowPrice From=sip:123@example.com To=sip:0031650222333@example.com Gateway=10.0.0.1 Duration=59\n". "DebitBalance CallId=6432622xvv@1 From=sip:123@example.com To=sip:0031650222333@example.com Gateway=10.0.0.1 Duration=59\n". "AddBalance From=123@example.com Value=10.00\n". "GetBalance From=123@example.com\n". "GetBalanceHistory From=123@example.com\n". "DeleteBalance From=123@example.com\n". "DeleteBalanceHistory From=123@example.com\n". "ReloadQuota Account=abc@example.com\n". "GetEntityProfiles Entity=abc@example.com\n". "DumpPrepaidSessions Account=123@example.com\n". "ReloadRatingTables\n". "ReloadDomains\n". "ShowProfiles\n". "ShowENUMtlds\n" ; return $help; } function logRuntime() { if (!$this->log_runtime) return; $t=0; $log=''; foreach (array_keys($this->runtime) as $_key) { $stamp=$this->runtime[$_key]; if ($prev_stamp) { $_exec_time = $stamp - $prev_stamp; $log .= sprintf("%s=%1.7f ", $_key, $_exec_time); } $prev_stamp = $stamp; $t++; } syslog(LOG_NOTICE, $log); } function processNetworkInput($tinput) { // Read key=value pairs from input // Strip any unnecessary spaces $this->runtime = array(); $tinput = preg_replace("/\s+/", " ", $tinput); if ($tinput == "/" and strlen($this->last_input)) { $tinput = $this->last_input; } else { $this->last_input = $tinput; } $_els = explode(" ", trim($tinput)); $this->runtime['start']=microtime_float(); syslog(LOG_NOTICE, "Got command: $tinput"); if (!$_els[0]) return 0; // read fields from input unset($NetFields); unset($seenField); $i=0; while ($i < count($_els)) { $i++; $_dict = explode("=", $_els[$i]); $_key = strtolower(trim($_dict[0])); if ($_key == 'callid') { $_value = trim($_dict[1]); } else { $_value = strtolower(trim($_dict[1])); } if ($_key && $seenField[$_key]) { $log = sprintf( "Error: '$_key' attribute is present more than once in $tinput" ); syslog(LOG_NOTICE, $log); return 0; } else { if ($_key) { $NetFields[$_key]=$_value; $seenField[$_key]++; } } } $NetFields['action'] = strtolower($_els[0]); $this->method = $NetFields['action']; // begin processing if ($NetFields['action']=="maxsessiontime") { if (!$NetFields['from']) { $log = "Error: missing From parameter"; syslog(LOG_NOTICE, $log); return $log; } if (!$NetFields['to']) { $log = "Error: missing To parameter"; syslog(LOG_NOTICE, $log); return $log; } if (!$NetFields['gateway']) { $log = "Error: missing gateway parameter"; syslog(LOG_NOTICE, $log); return $log; } if (!$NetFields['callid']) { $log = "Error: missing Call Id parameter"; syslog(LOG_NOTICE, $log); return $log; } if (!$NetFields['duration'] && $this->settings['MaxSessionTime']) { $NetFields['duration']=$this->settings['MaxSessionTime']; } $app_prefix = preg_replace('/[.].*$/', '', $NetFields['application']); if (strlen($app_prefix)) { if ($app_prefix == 'audio' || $app_prefix == 'sms') { $application=$NetFields['application']; } else { $log = sprintf( "Error: unsupported application %s", $NetFields['application'] ); syslog(LOG_NOTICE, $log); return $log; } } else { $application='audio'; } list($username_t, $domain_t) = explode("@", $NetFields['from']); $CDRStructure = array( $this->CDRS->CDRFields['callId'] => $NetFields['callid'], $this->CDRS->CDRFields['aNumber'] => $NetFields['from'], $this->CDRS->CDRFields['CanonicalURI'] => $NetFields['to'], $this->CDRS->CDRFields['gateway'] => $NetFields['gateway'], $this->CDRS->CDRFields['duration'] => floor($NetFields['duration']), $this->CDRS->CDRFields['timestamp'] => time(), $this->CDRS->CDRFields['domain'] => $domain_t, $this->CDRS->CDRFields['application'] => $application, 'skip_fix_prepaid_duration' => true ); $CDR = new $this->CDRS->CDR_class($this->CDRS, $CDRStructure); $CDR->normalize(); $this->runtime['normalize_cdr'] = microtime_float(); $query = sprintf( "select * from %s where account = '%s'", addslashes($this->prepaid_table), addslashes($CDR->BillingPartyId) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for query '%s': %s (%s), link_id =%s, query_id =%s", $query, $this->db->Error, $this->db->Errno, $this->db->Link_ID, $this->db->Query_ID ); syslog(LOG_NOTICE, $log); $this->logRuntime(); $ret = sprintf( "Error: database error for query '%s': %s (%s)", $query, $this->db->Error, $this->db->Errno )."\n"."type=prepaid"; return $ret; } if (!$this->db->num_rows()) { $log = sprintf( "MaxSessionTime=unlimited Type=postpaid CallId=%s BillingParty=%s", $NetFields['callid'], $CDR->BillingPartyId ); syslog(LOG_NOTICE, $log); $ret="none"."\n"."type=postpaid"; return $ret; } $this->db->next_record(); $current_balance = $this->db->f('balance'); $old_session_counter = $this->db->f('session_counter'); $max_sessions = $this->db->f('max_sessions'); if (strlen($this->db->f('active_sessions'))) { // load active sessions $active_sessions = json_decode($this->db->f('active_sessions'), true); if (count($active_sessions)) { // purge stale sessions $active_sessions_new=array(); $expired=0; foreach (array_keys($active_sessions) as $_session) { $expired_since = time() - $active_sessions[$_session]['timestamp'] - $active_sessions[$_session]['MaxSessionTime']; if ($expired_since > 120) { // this session has passed its maxsessiontime plus its reasonable setup time of 2 minutes, // it could be stale // because the call control module did not call debitbalance, so we purge it $log = sprintf( "Session %s for %s has expired since %d seconds", $_session, $active_sessions[$_session]['BillingPartyId'], $expired_since ); syslog(LOG_NOTICE, $log); $expired++; } else { $active_sessions_new[$_session]=$active_sessions[$_session]; } } if ($expired) { $active_sessions=$active_sessions_new; } } } else { $active_sessions=array(); } if (!$current_balance) { $log = "No balance found"; syslog(LOG_NOTICE, $log); $this->logRuntime(); $ret="0"."\n"."type=prepaid"; return $ret; } if (preg_match("/^0[0-9]{1,}@/", $CDR->CanonicalURINormalized)) { if (!$CDR->DestinationId) { $log = sprintf( "Error: cannot figure out the destination id for %s", $CDR->CanonicalURI ); $this->logRuntime(); syslog(LOG_NOTICE, $log); $ret=$log."\n"."type=prepaid"; return $ret; } } else { $log = sprintf( "MaxSessionTime=unlimited Type=prepaid CallId=%s BillingParty=%s DestId=None", $NetFields['callid'], $CDR->BillingPartyId ); syslog(LOG_NOTICE, $log); $this->logRuntime(); $ret="none"."\n"."type=prepaid"; return $ret; } $session_counter=count($active_sessions); if ($max_sessions && $session_counter >= $max_sessions) { $log = sprintf( "Locked: maximum number of concurrent calls %s reached, %s allowed", $session_counter, $max_sessions ); syslog(LOG_NOTICE, $log); $ret="Locked"."\n"."type=prepaid"; return $ret; } $maxduration=0; // Build Rate dictionary containing normalized CDR fields plus customer Balance if (count($active_sessions)) { // set $this->remaining_balance and $this->parallel_calls for ongoing calls: if (!$this->getActivePrepaidSessions($active_sessions, $current_balance, $CDR->BillingPartyId, array($CDR->callId))) { $ret="0"."\n"."type=prepaid"; return $ret; } $this->runtime['get_parallel_calls']=microtime_float(); // add this new call to the list of parallel calls $RateDictionary = array( 'duration' => $CDR->duration, 'callId' => $CDR->callId, 'Balance' => $this->remaining_balance, 'timestamp' => $CDR->timestamp, 'DestinationId' => $CDR->DestinationId, 'region' => $CDR->region, 'domain' => $CDR->domain, 'gateway' => $CDR->gateway, 'BillingPartyId' => $CDR->BillingPartyId, 'ENUMtld' => $CDR->ENUMtld, 'RatingTables' => $this->CDRS->RatingTables, 'application' => $application ); $Rate = new Rate($this->settings, $this->db); $_maxduration = round($Rate->MaxSessionTime($RateDictionary)); $log = sprintf( "Maximum duration for new session %s of %s to destination %s having balance=%s is %s", $CDR->callId, $CDR->BillingPartyId, $CDR->DestinationId, $this->remaining_balance, $_maxduration ); syslog(LOG_NOTICE, $log); if ($_maxduration > 0) { $this->parallel_calls[$CDR->callId] = array( 'remainingBalancePerSecond' => $this->remaining_balance / $_maxduration ); } else { $log = sprintf( "Maximum duration for new session %s of %s <=0", $CDR->callId, $CDR->BillingPartyId ); syslog(LOG_NOTICE, $log); $ret="0"."\n"."type=prepaid"; return $ret; } $this->parallel_calls[$CDR->callId]=array('remainingBalancePerSecond' => $this->remaining_balance/$_maxduration); $maxduration=$this->getAggregatedMaxSessiontime($this->parallel_calls, $this->remaining_balance, $CDR->BillingPartyId); } else { $RateDictionary=array( 'duration' => $CDR->duration, 'callId' => $CDR->callId, 'Balance' => $current_balance, 'timestamp' => $CDR->timestamp, 'DestinationId' => $CDR->DestinationId, 'region' => $CDR->region, 'domain' => $CDR->domain, 'gateway' => $CDR->gateway, 'BillingPartyId' => $CDR->BillingPartyId, 'ENUMtld' => $CDR->ENUMtld, 'RatingTables' => $this->CDRS->RatingTables, 'application' => $application ); $Rate = new Rate($this->settings, $this->db); $this->runtime['instantiate_rate']=microtime_float(); $maxduration = round($Rate->MaxSessionTime($RateDictionary)); } // add new active session $active_sessions[$CDR->callId] = array( 'timestamp' => $CDR->timestamp, 'duration' => $CDR->duration, 'BillingPartyId' => $CDR->BillingPartyId, 'MaxSessionTime' => $maxduration, 'domain' => $CDR->domain, 'gateway' => $CDR->gateway, 'Destination' => $CDR->destinationPrint, 'DestinationId' => $CDR->DestinationId, 'region' => $CDR->region, 'connectCost' => $Rate->connectCost ); if ($CDR->ENUMtld) { $active_sessions[$CDR->callId]['ENUMtld']=$CDR->ENUMtld; } $this->runtime['calculate_maxduration']=microtime_float(); if ($maxduration < 0) { $log = sprintf( "Error: maxduration %s is negative", $maxduration ); syslog(LOG_NOTICE, $log); $ret = $log."\n"."type=prepaid"; return $ret; } if ($Rate->min_duration && $maxduration < $Rate->min_duration) { $log = sprintf( "Notice: maxduration of %s is less then min_duration (%s)", $maxduration, $Rate->min_duration ); syslog(LOG_NOTICE, $log); $ret = "0"."\n"."type=prepaid"; return $ret; } if (!$Rate->billingTimezone) { $log = sprintf("Error: cannot figure out the billing timezone")."\n"."type=prepaid"; syslog(LOG_NOTICE, $log); $ret=$log."\n"."type=prepaid"; return $ret; } if (!$Rate->startTimeBilling) { $log = sprintf("Error: cannot figure out the billing start time")."\n"."type=prepaid"; syslog(LOG_NOTICE, $log); $ret = $log."\n"."type=prepaid"; return $ret; } $log = sprintf( "MaxSessionTime=%s Type=prepaid CallId=%s BillingParty=%s DestId=%s Balance=%s Spans=%d Counter=%d->%d", $maxduration, $NetFields['callid'], $CDR->BillingPartyId, $CDR->DestinationId, $RateDictionary['Balance'], $Rate->MaxSessionTimeSpans, $old_session_counter, count($active_sessions) ); syslog(LOG_NOTICE, $log); if ($maxduration > 0) { $query = sprintf( "update %s set active_sessions = '%s', session_counter = '%s' where account = '%s'", addslashes($this->prepaid_table), addslashes(json_encode($active_sessions)), count($active_sessions), addslashes($CDR->BillingPartyId) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); $log= sprintf( "Error: database error %s (%s)", $this->db->Error, $this->db->Errno ); return $log; } } $this->runtime['update_prepaid']=microtime_float(); $this->logRuntime(); $ret=$maxduration."\n"."type=prepaid"; return $ret; } elseif ($NetFields['action'] == "dumpprepaidsessions") { if (!$NetFields['account']) { $log = "Error: missing account parameter"; syslog(LOG_NOTICE, $log); return $log; } $query = sprintf( "select * from %s where account = '%s'", addslashes($this->prepaid_table), addslashes($NetFields['account']) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); $this->logRuntime(); return 0; } if (!$this->db->num_rows()) { $log = sprintf("DebitBalanceAudio() Error: account %s does not exist", $account); syslog(LOG_NOTICE, $log); $this->logRuntime(); return 0; } $this->db->next_record(); return var_export(json_decode($this->db->f('active_sessions'), true), true); } elseif ($NetFields['action'] == "debitbalance") { if (!$NetFields['from']) { $log = "Error: missing From parameter"; syslog(LOG_NOTICE, $log); return $log; } if (!$NetFields['to']) { $log = "Error: missing To parameter"; syslog(LOG_NOTICE, $log); return $log; } $app_prefix = preg_replace('/[.].*$/', '', $NetFields['application']); if (!strlen($app_prefix) || (strlen($app_prefix) && $app_prefix == 'audio')) { if (!strlen($NetFields['duration'])) { $log= "Error: missing Duration parameter"; syslog(LOG_NOTICE, $log); return $log; } } if (strlen($app_prefix)) { if ($app_prefix == 'audio' || $app_prefix == 'sms') { $application = $NetFields['application']; } else { $log = sprintf("Error: unsupported application %s", $NetFields['application']); syslog(LOG_NOTICE, $log); return $log; } } else { $application = 'audio'; $app_prefix = 'audio'; } if (!$NetFields['gateway']) { $log = "Error: missing gateway parameter"; syslog(LOG_NOTICE, $log); return $log; } if (!$NetFields['callid']) { $log = "Error: missing Call Id parameter"; syslog(LOG_NOTICE, $log); return $log; } if ($NetFields['force']) { $force = true; } else { $force = false; } $timestamp = time(); list($username_t, $domain_t) = explode("@", $NetFields['from']); $CDRStructure = array( $this->CDRS->CDRFields['callId'] => $NetFields['callid'], $this->CDRS->CDRFields['aNumber'] => $NetFields['from'], $this->CDRS->CDRFields['CanonicalURI'] => $NetFields['to'], $this->CDRS->CDRFields['gateway'] => $NetFields['gateway'], $this->CDRS->CDRFields['ENUMtld'] => $NetFields['enumtld'], $this->CDRS->CDRFields['duration'] => floor($NetFields['duration']), $this->CDRS->CDRFields['timestamp'] => time(), $this->CDRS->CDRFields['domain'] => $domain_t, $this->CDRS->CDRFields['application'] => $application, 'skip_fix_prepaid_duration' => true ); // Init CDR $CDR = new $this->CDRS->CDR_class($this->CDRS, $CDRStructure); $CDR->normalize(); $this->runtime['normalize_cdr']=microtime_float(); // Build Rate dictionary containing normalized CDR fields plus customer Balance $RateDictionary = array( 'callId' => $NetFields['callid'], 'timestamp' => $CDR->timestamp, 'duration' => $CDR->duration, 'DestinationId' => $CDR->DestinationId, 'region' => $CDR->region, 'domain' => $CDR->domain, 'gateway' => $CDR->gateway, 'BillingPartyId' => $CDR->BillingPartyId, 'ENUMtld' => $CDR->ENUMtld, 'RatingTables' => $this->CDRS->RatingTables, 'application' => $application ); $Rate = new Rate($this->settings, $this->db); $this->runtime['instantiate_rate']=microtime_float(); if ($app_prefix == 'audio') { if ($Rate->calculateAudio($RateDictionary)) { $this->runtime['calculate_rate'] = microtime_float(); $this->sessionDoesNotExist = false; $result = $this->DebitBalanceAudio( $CDR->BillingPartyId, $Rate->price, $NetFields['callid'], $CDR->duration, $force ); if ($this->sessionDoesNotExist) { return "Failed"; } $this->runtime['debit_balance']=microtime_float(); $log = sprintf( "DebitBalance=%s Duration=%s CallId=%s BillingParty=%s DestId=%s MaxSessionTime=%d Counter=%d->%d", $Rate->price, $CDR->duration, $NetFields['callid'], $CDR->BillingPartyId, $CDR->DestinationId, $result, $this->old_session_count, $this->new_session_count ); syslog(LOG_NOTICE, $log); $RateReturn = "Ok"; $RateReturn.= sprintf("\nMaxSessionTime=%d", $result); if (strlen($Rate->price)) { $RateReturn.="\n".$Rate->price; if ($Rate->rateInfo) { $RateReturn.="\n".trim($Rate->rateInfo); } } return $RateReturn; } else { syslog(LOG_NOTICE, 'Failed to calculate rate in DebitBalance()'); return "Failed\n"; } } elseif ($app_prefix == 'sms') { // return Ok, No credit, Error if ($Rate->calculateMessage($RateDictionary)) { if ($this->DebitBalanceMessage($CDR->BillingPartyId, $CDR->destinationPrint, $Rate->price, $NetFields['callid'])) { $log = sprintf( "Price=%s CallId=%s BillingParty=%s DestId=%s Application=%s", $Rate->price, $NetFields['callid'], $CDR->BillingPartyId, $CDR->DestinationId, $application ); syslog(LOG_NOTICE, $log); $RateReturn = "Ok"; if (strlen($Rate->price)) { $RateReturn.="\n".$Rate->price; if ($Rate->rateInfo) { $RateReturn.="\n".trim($Rate->rateInfo); } } return $RateReturn; } else { return "Failed"; } } else { return "Failed"; } } else { return false; } } elseif ($NetFields['action'] == "addbalance") { if (!$NetFields['from']) { $log = "Error: Missing From parameter"; syslog(LOG_NOTICE, $log); return 0; } if (!is_numeric($NetFields['value'])) { $log = "Error: Missing Value parameter, it must be numeric"; syslog(LOG_NOTICE, $log); return 0; } return $this->CreditBalance($NetFields['from'], $NetFields['value']); } elseif ($NetFields['action'] == "deletebalance") { if (!$NetFields['from']) { $log = "Error: Missing From parameter"; syslog(LOG_NOTICE, $log); return 0; } return $this->DeleteBalance($NetFields['from']); } elseif ($NetFields['action'] == "deletebalancehistory") { if (!$NetFields['from']) { $log = "Error: Missing From parameter"; syslog(LOG_NOTICE, $log); return 0; } return $this->DeleteBalanceHistory($NetFields['from']); } elseif ($NetFields['action'] == "showprice") { if (!$NetFields['from']) { $log = "Error: Missing From parameter"; syslog(LOG_NOTICE, $log); return 0; } if (!$NetFields['to']) { $log = "Error: Missing To parameter"; syslog(LOG_NOTICE, $log); return 0; } if (!strlen($NetFields['duration'])) { $log = "Error: Missing Duration parameter"; syslog(LOG_NOTICE, $log); return 0; } if ($NetFields['timestamp']) { $timestamp = $NetFields['timestamp']; } else { $timestamp = time(); } if (!$NetFields['gateway']) { $log = "Error: missing gateway parameter"; syslog(LOG_NOTICE, $log); return $log; } $app_prefix = preg_replace('/[.].*$/', '', $NetFields['application']); if (strlen($app_prefix)) { if ($app_prefix == 'audio' || $app_prefix == 'sms') { $application = $NetFields['application']; } else { $log = sprintf("Error: unsupported application %s", $NetFields['application']); syslog(LOG_NOTICE, $log); return $log; } } else { $application = 'audio'; } list($username_t, $domain_t) = explode("@", $NetFields['from']); $CDRStructure=array ( $this->CDRS->CDRFields['callId'] => $NetFields['callid'], $this->CDRS->CDRFields['aNumber'] => $NetFields['from'], $this->CDRS->CDRFields['CanonicalURI'] => $NetFields['to'], $this->CDRS->CDRFields['gateway'] => $NetFields['gateway'], $this->CDRS->CDRFields['ENUMtld'] => $NetFields['enumtld'], $this->CDRS->CDRFields['duration'] => floor($NetFields['duration']), $this->CDRS->CDRFields['timestamp'] => time(), $this->CDRS->CDRFields['domain'] => $domain_t, $this->CDRS->CDRFields['application'] => $application, 'skip_fix_prepaid_duration' => true ); $CDR = new $this->CDRS->CDR_class($this->CDRS, $CDRStructure); $CDR->normalize(); $Rate = new Rate($this->settings, $this->db); $RateDictionary=array( 'callId' => $CDR->callId, 'timestamp' => $CDR->timestamp, 'duration' => $CDR->duration, 'DestinationId' => $CDR->DestinationId, 'region' => $CDR->region, 'domain' => $CDR->domain, 'gateway' => $CDR->gateway, 'BillingPartyId' => $CDR->BillingPartyId, 'ENUMtld' => $CDR->ENUMtld, 'RatingTables' => $this->CDRS->RatingTables, 'application' => $application ); $Rate->calculateAudio($RateDictionary); $this->runtime['calculate_rate'] = microtime_float(); if (strlen($Rate->price)) { $RateReturn=$Rate->price; if ($Rate->rateInfo) { $RateReturn.="\n".trim($Rate->rateInfo); } } else { $RateReturn="0"; } return $RateReturn; } elseif ($NetFields['action'] == "getbalance") { if (!$NetFields['from']) { $log = "Error: Missing From parameter"; syslog(LOG_NOTICE, $log); return 0; } $query = sprintf( "select * from %s where account = '%s'", addslashes($this->prepaid_table), addslashes($NetFields['from']) ); if (!$this->db->query($query)) { $log = sprintf( "Database error for %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); $this->logRuntime(); return 0; } if ($this->db->num_rows()) { $this->db->next_record(); return number_format($this->db->f('balance'), 4, ".", ""); } else { return sprintf("%0.4f", 0); } } elseif ($NetFields['action'] == "getbalancehistory") { if (!$NetFields['from']) { $log = "Error: Missing From parameter"; syslog(LOG_NOTICE, $log); return 0; } $history=$this->getBalanceHistory($NetFields['from']); return trim($history); } elseif ($NetFields['action'] == "getentityprofiles") { if (!$NetFields['entity']) { $log = "Error: Missing Entity parameter"; syslog(LOG_NOTICE, $log); return 0; } $entity=$this->GetEntityProfiles($NetFields['entity']); return trim($entity); } elseif ($NetFields['action'] == "showprofiles") { return trim($this->CDRS->RatingTables->showProfiles()); } elseif ($NetFields['action'] == "showenumtlds") { return trim($this->CDRS->RatingTables->showENUMtlds()); } elseif ($NetFields['action'] == "version") { $version_file=$this->CDRS->CDRTool['Path']."/version"; $version="CDRTool version ".trim(file_get_contents($version_file)); return $version; } elseif ($NetFields['action'] == "help") { return $this->showHelp(); } elseif ($NetFields['action'] == "reloadratingtables") { return $this->reloadRatingTables(); } elseif ($NetFields['action'] == "keepalive") { return $this->keepAlive(); } elseif ($NetFields['action'] == "reloadquota") { if (!$NetFields['account']) { $log = "Error: Missing Account parameter"; syslog(LOG_NOTICE, $log); return 0; } return $this->reloadQuota($NetFields['account']); } elseif ($NetFields['action'] == "reloaddomains") { return $this->CDRS->LoadDomains(); } elseif ($NetFields['action'] == "reloadcustomers") { if ($NetFields['customer'] && $NetFields['type']) { $_customerFilter = array( 'customer' => $NetFields['customer'], 'type' => $NetFields['type'] ); } return $this->reloadCustomers($_customerFilter); } else { $log = "Error: Invalid request"; syslog(LOG_NOTICE, $log); return 0; } } function getQuota($account) { if (!$account) return; list($username, $domain) = explode("@", $account); if ($this->enableThor) { $query = sprintf( "select * from sip_accounts where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain) ); if (!$this->AccountsDB->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno ); syslog(LOG_NOTICE, $log); return 0; } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); $_profile=json_decode(trim($this->AccountsDB->f('profile'))); return $_profile->quota; } else { return 0; } } else { $query = sprintf( "select quota from subscriber where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain) ); if (!$this->AccountsDB->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno ); syslog(LOG_NOTICE, $log); return 0; } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); return $this->AccountsDB->f('quota'); } else { return 0; } } } function getBlockedByQuotaStatus($account) { if (!$account) return 0; list($username, $domain) = explode("@", $account); if ($this->enableThor) { $query = sprintf( "select * from sip_accounts where username = '%s' and domain = '%s'", addslashes($username), addslashes($domain) ); if (!$this->AccountsDB->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno ); syslog(LOG_NOTICE, $log); return 0; } if ($this->AccountsDB->num_rows()) { $this->AccountsDB->next_record(); $_profile = json_decode(trim($this->AccountsDB->f('profile'))); if (in_array('quota', $_profile->groups)) { return 1; } else { return 0; } } else { return 0; } } else { $query = sprintf( "select CONCAT(username,'@',domain) as account from grp where grp = 'quota' and username = '%s' and domain = '%s'", addslashes($username), addslashes($domain) ); if (!$this->AccountsDB->query($query)) { $log = sprintf( "Database error for query %s: %s (%s)", $query, $this->AccountsDB->Error, $this->AccountsDB->Errno ); syslog(LOG_NOTICE, $log); return 0; } if ($this->AccountsDB->num_rows()) { return 1; } else { return 0; } } return 0; } function getActivePrepaidSessions($active_sessions, $current_balance, $BillingPartyId, $exceptSessions = array()) { $this->parallel_calls=array(); $this->remaining_balance=$current_balance; $ongoing_rates=array(); foreach (array_keys($active_sessions) as $_session) { if (in_array($_session, $exceptSessions)) { /* $log = sprintf ("Ongoing prepaid session %s for %s updated", $_session, $BillingPartyId ); syslog(LOG_NOTICE, $log); */ continue; } $Rate_session = new Rate($this->settings, $this->db); $passed_time = time() - $active_sessions[$_session]['timestamp']; $active_sessions[$_session]['passed_time'] = $passed_time; $RateDictionary_session = array( 'duration' => $passed_time, 'callId' => $_session, 'timestamp' => $active_sessions[$_session]['timestamp'], 'DestinationId' => $active_sessions[$_session]['DestinationId'], 'region' => $active_sessions[$_session]['region'], 'domain' => $active_sessions[$_session]['domain'], 'BillingPartyId' => $active_sessions[$_session]['BillingPartyId'], 'ENUMtld' => $active_sessions[$_session]['ENUMtld'], 'RatingTables' => $this->CDRS->RatingTables ); $Rate_session->calculateAudio($RateDictionary_session); $log = sprintf( "Active sessions %s for %s to %s: duration=%s, price=%s ", $_session, $BillingPartyId, $active_sessions[$_session]['Destination'], $passed_time, $Rate_session->price ); syslog(LOG_NOTICE, $log); $ongoing_rates[$_session] = array( 'duration' => $passed_time, 'price' => $Rate_session->price ); } if (count($ongoing_rates)) { // calculate the virtual balance of the user at this moment in time $due_balance=0; foreach (array_keys($ongoing_rates) as $_o) { $due_balance = $due_balance + $ongoing_rates[$_o]['price']; } $this->remaining_balance = $this->remaining_balance-$due_balance; $log = sprintf( "Balance for %s having %d active sessions: database=%s, due=%s, real=%s", $BillingPartyId, count($ongoing_rates), sprintf("%0.4f", $current_balance), sprintf("%0.4f", $due_balance), sprintf("%0.4f", $this->remaining_balance) ); syslog(LOG_NOTICE, $log); } foreach (array_keys($active_sessions) as $_session) { if (in_array($_session, $exceptSessions)) { continue; } $RateDictionary_session = array( 'callId' => $_session, 'timestamp' => time(), 'Balance' => $this->remaining_balance, 'DestinationId' => $active_sessions[$_session]['DestinationId'], 'region' => $active_sessions[$_session]['region'], 'domain' => $active_sessions[$_session]['domain'], 'BillingPartyId' => $active_sessions[$_session]['BillingPartyId'], 'ENUMtld' => $active_sessions[$_session]['ENUMtld'], 'RatingTables' => $this->CDRS->RatingTables, 'skipConnectCost' => true ); if ($active_sessions[$_session]['duration']) { $RateDictionary_session['duration'] = $active_sessions[$_session]['duration']-$active_sessions[$_session]['passed_time']; } $Rate = new Rate($this->settings, $this->db); $_maxduration = round($Rate->MaxSessionTime($RateDictionary_session)); $log = sprintf( "Remaining duration for active session %s of %s to destination %s having balance=%s is %s", $_session, $BillingPartyId, $active_sessions[$_session]['DestinationId'], $this->remaining_balance, $_maxduration ); syslog(LOG_NOTICE, $log); if ($_maxduration > 0) { $this->parallel_calls[$_session] = array( 'remainingBalancePerSecond' => $this->remaining_balance / $_maxduration ); } else { /* $log = sprintf ("Maxduration for session %s of %s will be negative",$_session,$active_sessions[$_session]['BillingPartyId']); syslog(LOG_NOTICE, $log); */ } } return 1; } function getAggregatedMaxSessiontime($parallel_calls = array(), $balance, $BillingPartyId) { $maxduration=0; $sum_remaining_balance_per_second=0; foreach (array_keys($parallel_calls) as $_call) { $sum_remaining_balance_per_second = $sum_remaining_balance_per_second + $parallel_calls[$_call]['remainingBalancePerSecond']; } if ($sum_remaining_balance_per_second > 0) { $maxduration = intval($balance / $sum_remaining_balance_per_second); if (count($parallel_calls) > 1) { $log = sprintf("Maximum agregated duration for %s is %s", $BillingPartyId, $maxduration); syslog(LOG_NOTICE, $log); } } else { /* $log = sprintf ("Error: sum_remaining_balance_per_second for %s is negative",$BillingPartyId); syslog(LOG_NOTICE, $log); */ $maxduration = 0; } return round($maxduration); } function keepAlive() { $query = sprintf("select * from auth_user"); if (!$this->db->query($query) || !$this->db->num_rows()) { $log = sprintf( "Database error for keepalive query %s: %s (%s)", $query, $this->db->Error, $this->db->Errno ); syslog(LOG_NOTICE, $log); return false; } $log = sprintf("Keepalive successful"); syslog(LOG_NOTICE, $log); return true; } } function reloadRatingEngineTables() { global $RatingEngine; global $DATASOURCES; if (strlen($RatingEngine['socketIP']) && $RatingEngine['socketPort']) { if ($RatingEngine['socketIP']=='0.0.0.0' || $RatingEngine['socketIP'] == '0') { $RatingEngine['socketIPforClients']= '127.0.0.1'; } else { $RatingEngine['socketIPforClients']=$RatingEngine['socketIP']; } // init CDR datasource $CDR_class = $DATASOURCES[$RatingEngine['cdr_source']]['class']; $CDRS = new $CDR_class($RatingEngine['cdr_source']); $CDRS->CacheDestinations(); if ($fp = fsockopen($RatingEngine['socketIPforClients'], $RatingEngine['socketPort'], $errno, $errstr, 2)) { fputs($fp, "ReloadRatingTables\n"); fclose($fp); return true; } } return false; } function keepAliveRatingEngine() { global $RatingEngine; if (strlen($RatingEngine['socketIP']) && $RatingEngine['socketPort']) { if ($RatingEngine['socketIP']=='0.0.0.0' || $RatingEngine['socketIP'] == '0') { $RatingEngine['socketIPforClients']= '127.0.0.1'; } else { $RatingEngine['socketIPforClients']=$RatingEngine['socketIP']; } if ($fp = fsockopen($RatingEngine['socketIPforClients'], $RatingEngine['socketPort'], $errno, $errstr, 2)) { fputs($fp, "KeepAlive\n"); fclose($fp); return true; } } return false; } function testRatingTables() { global $RatingEngine; if (!strlen($RatingEngine['socketIP']) || !$RatingEngine['socketPort']) { return false; } if ($RatingEngine['socketIP']=='0.0.0.0' || $RatingEngine['socketIP'] == '0') { $RatingEngine['socketIPforClients']= '127.0.0.1'; } else { $RatingEngine['socketIPforClients']=$RatingEngine['socketIP']; } $i=0; $b=time(); while ($i < 1000) { if (!$fp = fsockopen($RatingEngine['socketIPforClients'], $RatingEngine['socketPort'], $errno, $errstr, 2)) { print "Error connecting to rating engine\n"; break; } $i++; $number='00'.RandomNumber(1, true).RandomNumber(12).'@example.com'; $duration=RandomNumber(3, true); $command = sprintf( "ShowPrice From=sip:123@example.com To=sip:%s Gateway=10.0.0.1 Duration=%d\n", $number, $duration ); fputs($fp, $command, strlen($command)); $response = fgets($fp, 8192); fclose($fp); } $e = time(); $d = $e - $b; if ($d) { printf("Commands=%d, Time=%s seconds, Speed=%s cps\n", $i, $d, number_format($i / $d, 1)); } } ?> diff --git a/library/sip_settings.php b/library/sip_settings.php index f2998a8..108b832 100644 --- a/library/sip_settings.php +++ b/library/sip_settings.php @@ -1,13119 +1,12961 @@ "; var $billing_email = "Billing "; var $sip_settings_page = "https://cdrtool.example.com/sip_settings.phtml"; var $xcap_root = "https://cdrtool.example.com/xcap-root"; var $pstn_access = false; var $sms_access = false; var $pstn_changes_allowed = false; var $prepaid_changes_allowed = false; var $sip_proxy = "proxy.example.com"; var $sip_outbound_proxy = ""; var $sip_mobile_outbound_proxy = ""; var $voicemail_server = "vm.example.com"; var $absolute_voicemail_uri = false; // use var $enable_thor = false; var $currency = "€"; // access numbers var $voicemail_access_number = "1233"; var $FUNC_access_number = "*21*"; var $FNOL_access_number = "*22*"; var $FNOA_access_number = "*23*"; var $FBUS_access_number = "*23*"; var $change_privacy_access_number = "*67"; var $check_privacy_access_number = "*68"; var $reject_anonymous_access_number = "*69"; var $show_barring_tab = false; var $show_payments_tab = false; var $show_tls_section = false; var $show_support_tab = false; var $show_did_tab = false; var $show_directory = false; var $notify_on_sip_account_changes = false; var $first_tab = 'calls'; var $auto_refesh_tab = 0; // number of seconds after which to refresh tab content in the web browser var $payment_processor_class = false; var $did_processor_class = false; var $show_download_tab = 'Blink'; // set it to name of the tab or false to disable it var $digest_settings_page = "https://blink.sipthor.net/settings.phtml"; // end variables var $tab = "settings"; var $phonebook_img = ""; var $call_img = "

"; var $delete_img = "Delete"; var $plus_sign_img = "Add Contact"; var $embedded_img = ""; var $groups = array(); var $form_elements = array( 'mailto', 'free-pstn', 'blocked', 'sip_password', 'web_password', 'yubikey', 'first_name', 'last_name', 'quota', 'language', 'quota_deblock', 'voicemail', 'anonymous', 'advanced', 'rpid', 'timezone', 'accept', 'accept_temporary_group', 'accept_temporary_remain', 'web_timestamp', 'web_password_reset', 'acceptDailyStartTime', 'acceptDailyStopTime', 'acceptDailyGroup', 'quickdial', 'delete_voicemail', 'voicemail_password', 'region', 'timeout', 'owner', 'mobile_number', 'extra_groups', 'show_barring_tab', 'ip_access_list', 'callLimit' ); var $disable_extra_groups=true; var $prepaid = 0; var $emergency_regions = array(); var $FNOA_timeoutDefault = 35; var $enums = array(); var $barring_prefixes = array(); var $SipUAImagesPath = "images"; var $SipUAImagesFile = "phone_images.php"; var $balance_history = array(); var $enrollment_url = false; var $sip_settings_api_url= false; var $journalEntries = array(); - var $chat_replication_backend = 'mysql'; // mongo or mysql + var $chat_replication_backend = 'mysql'; var $owner_information =array(); var $languages=array("en"=>array('name'=>"English", 'timezone'=>'' ), "ro"=>array('name'=>"Română", 'timezone' => 'Europe/Bucharest' ), "nl"=>array('name'=>"Nederlands", 'timezone' => 'Europe/Amsterdam' ), "es"=>array('name'=>"Español", 'timezone' => 'Europe/Madrid' ), "de"=>array('name'=>"Deutsch", 'timezone' => 'Europe/Berlin' ) ); var $pstn_termination_price_page = 'sip_rates_body.html'; var $append_domain_to_xcap_root = false; var $blink_download_url = "https://blink.sipthor.net/download.phtml?download"; var $ownerCredentials = array(); var $localGroups = array(); var $max_credit_per_day = 40; var $enrollment_configuration = "/etc/cdrtool/enrollment/config.ini"; var $require_proof_of_identity = true; var $call_limit_may_by_changed_by = 'reseller'; #subscriber, reseller, admin var $ip_access_list_may_by_changed_by = 'reseller'; #subscriber, reseller, admin var $create_certificate = false; function SipSettings($account,$loginCredentials=array(),$soapEngines=array()) { //define_syslog_variables(); $this->platform_call_limit = _('unlimited'); $this->soapEngines = $soapEngines; $debug=sprintf("

Initialize %s(%s)",get_class($this),$account); dprint($debug); //dprint_r($loginCredentials); $this->loginCredentials = &$loginCredentials; if ($this->isEmbedded()) { $this->login_type = 'subscriber'; } else { if ($loginCredentials['login_type']) { $this->login_type = $loginCredentials['login_type']; } else { $this->login_type = 'subscriber'; } } $this->reseller = $loginCredentials['reseller']; $this->customer = $loginCredentials['customer']; if (strlen($loginCredentials['sip_engine'])) { $this->sip_engine=$loginCredentials['sip_engine']; } else { print _("Error: missing sip_engine in login credentials"); return false; } $this->settingsPage = $_SERVER['PHP_SELF']; if ($_REQUEST['tab']) { $this->tab = $_REQUEST['tab']; } else { $this->tab = $this->first_tab; } $this->initSoapClient(); $this->getAccount($account); if ($this->tab=='calls' && !$_REQUEST['export']) { $this->auto_refesh_tab=180; } $this->admin_url = $this->settingsPage."?account=$this->account&adminonly=1&reseller=$this->reseller&sip_engine=$this->sip_engine"; $this->reseller_url = $this->settingsPage."?account=$this->account&reseller=$this->reseller&sip_engine=$this->sip_engine"; $this->admin_url_absolute = $this->sip_settings_page."?account=$this->account&adminonly=1&reseller=$this->reseller&sip_engine=$this->sip_engine"; if ($this->login_type == "admin") { $this->url=$this->admin_url; $this->hiddenElements=" account\"> reseller> sip_engine> "; } else if ($this->login_type == "reseller" || $this->login_type == "customer") { $this->url=$this->reseller_url; $this->hiddenElements=" account\"> reseller> sip_engine> "; } else { $this->url=$this->settingsPage; if (!$this->isEmbedded()) { $this->url.="?account=$this->account"; } else { $this->url.=sprintf("?1=1&realm=%s",urlencode($_REQUEST['realm'])); if ($_REQUEST['user_agent']) { $this->url.=sprintf("&user_agent=%s",urlencode($_REQUEST['user_agent'])); } } $this->hiddenElements=sprintf(" ", $this->account, $this->sip_engine, $_REQUEST['user_agent'], $_REQUEST['realm'] ); } $this->setLanguage(); if (!$this->username) { dprint ("Record not found."); return false; } $this->availableGroups['blocked'] = array("Group"=>"blocked", "WEBName" =>sprintf(_("Status")), "SubscriberMayEditIt"=>0, "SubscriberMaySeeIt"=>0, "ResellerMayEditIt"=>1, "ResellerMaySeeIt"=>1 ); $this->availableGroups['trunking'] = array("Group"=>"trunking", "WEBName" =>sprintf(_("Trunking")), "SubscriberMayEditIt"=>0, "SubscriberMaySeeIt"=>0, "ResellerMayEditIt"=>1, "ResellerMaySeeIt"=>1 ); $this->availableGroups['deny-password-change'] = array("Group"=>"deny-password-change", "WEBName" =>sprintf(_("Deny password change")), "SubscriberMayEditIt"=>0, "SubscriberMaySeeIt"=>0, "ResellerMayEditIt"=>1, "ResellerMaySeeIt"=>1 ); $this->getResellerSettings(); $this->getCustomerSettings(); if ($this->reject_anonymous_access_number) { $_comment = sprintf(_("Dial %s to change"), $this->reject_anonymous_access_number); } else { $_comment = ''; } $this->availableGroups['anonymous-reject']=array("Group"=>$this->anonymous-reject, "WEBName" =>sprintf (_("Reject Anonymous")), "WEBComment"=>$_comment, "SubscriberMaySeeIt"=>1, "SubscriberMayEditIt"=>1, "ResellerMayEditIt"=>1, "ResellerMaySeeIt"=>1 ); $this->availableGroups['missed-calls']=array("Group"=>'missed-calls', "WEBName" =>sprintf (_("Email Missed Calls")), "WEBComment"=>'', "SubscriberMaySeeIt"=>1, "SubscriberMayEditIt"=>1, "ResellerMayEditIt"=>1, "ResellerMaySeeIt"=>1 ); $this->availableGroups=array_merge($this->availableGroups, $this->localGroups); $this->pstnChangesAllowed(); $this->smsChangesAllowed(); $this->prepaidChangesAllowed(); $this->tabs=array('identity'=>_('Identity'), 'devices'=>_('Devices'), 'settings'=>_('Settings'), 'calls'=>_('History'), ); if (!in_array("trunking",$this->groups)) { $this->tabs['diversions']=_('Forwarding'); $this->tabs['accept']=_('Accept'); $this->tabs['contacts']=_('Contacts'); } if (in_array("free-pstn",$this->groups)) { if ($this->show_barring_tab || $this->Preferences['show_barring_tab']) { $this->tabs['barring']=_("Barring"); } } if ($this->show_did_tab && !in_array("trunking",$this->groups)) { $this->tabs['did']=_("DID"); } if (!$this->isEmbedded() && $this->show_download_tab && !in_array("trunking",$this->groups)) { $this->tabs['download'] = $this->show_download_tab; } $this->acceptDailyProfiles=array('127' => _('Every day'), '31' => _('Weekday'), '96' => _('Weekend'), '1' => _('Monday'), '2' => _('Tuesday'), '4' => _('Wednesday'), '8' => _('Thursday'), '16' => _('Friday'), '32' => _('Saturday'), '64' => _('Sunday') ); $this->PhonebookGroups=array( "vip" =>sprintf(_("VIP")), "business" =>sprintf(_("Business")), "coworkers" =>sprintf(_("Coworkers")), "friends" =>sprintf(_("Friends")), "family" =>sprintf(_("Family")) ); $this->diversionType=array( "FUNC"=>sprintf(_("All Calls")), "FNOL"=>sprintf(_("If Not-Online")), "FBUS"=>sprintf(_("If Busy")), "FNOA"=>sprintf(_("If No-Answer")), "FUNV"=>sprintf(_("If Unavailable")) ); $this->diversionTypeUNV=array( "FUNV"=>sprintf(_("If Unavailable")) ); $this->VoicemaildiversionType=array( "FNOL"=>sprintf(_("If Not-Online")), "FBUS"=>sprintf(_("If Busy")), "FNOA"=>sprintf(_("If No-Answer")), "FUNV"=>sprintf(_("If Unavailable")) ); $this->access_numbers=array("FUNC"=>$this->FUNC_access_number, "FNOA"=>$this->FNOA_access_number, "FBUS"=>$this->FBUS_access_number, "FNOL"=>$this->FNOL_access_number ); if ($this->prepaid && $this->pstn_access) { $this->tabs['credit']=_("Credit"); } $_protocol=preg_match("/^(https?:\/\/)/",$_SERVER['SCRIPT_URI'],$m); $this->absolute_url=$m[1].$_SERVER['HTTP_HOST'].$this->url; if ($this->prepaid && $this->show_payments_tab) { $this->tabs['payments']=_("Payments"); } if ($this->show_support_tab) { $this->tabs['support'] = 'Support'; } } function initSoapClient() { dprint("initSoapClient()"); // Sip, Voicemail and Customer ports share same login $this->SOAPurl=$this->soapEngines[$this->sip_engine]['url']; $this->SOAPversion=$this->soapEngines[$this->sip_engine]['version']; if ($this->soapEngines[$this->sip_engine]['enrollment_url']) { $this->enrollment_url =$this->soapEngines[$this->sip_engine]['enrollment_url']; } if ($this->soapEngines[$this->sip_engine]['chat_replication_backend']) { $this->chat_replication_backend = $this->soapEngines[$this->sip_engine]['chat_replication_backend']; } - if ($this->soapEngines[$this->sip_engine]['mongo_db']) { - $this->mongo_db = $this->soapEngines[$this->sip_engine]['mongo_db']; - } - if ($this->soapEngines[$this->sip_engine]['sip_settings_api_url']) { $this->sip_settings_api_url =$this->soapEngines[$this->sip_engine]['sip_settings_api_url']; } if (strlen($this->loginCredentials['soapUsername'])) { $this->SOAPlogin = array( "username" => $this->loginCredentials['soapUsername'], "password" => $this->loginCredentials['soapPassword'], "admin" => false ); $this->soapUsername = $this->loginCredentials['soapUsername']; } else { $this->SOAPlogin = array( "username" => $this->soapEngines[$this->sip_engine]['username'], "password" => $this->soapEngines[$this->sip_engine]['password'], "admin" => true, "impersonate" => intval($this->customer) ); $this->soapUsername = $this->soapEngines[$this->sip_engine]['username']; } $this->SoapAuth = array('auth', $this->SOAPlogin , 'urn:AGProjects:NGNPro', 0, ''); //print_r($this->SoapAuth); $this->SOAPloginAdmin = array( "username" => $this->soapEngines[$this->sip_engine]['username'], "password" => $this->soapEngines[$this->sip_engine]['password'], "admin" => true ); $this->SoapAuthAdmin = array('auth', $this->SOAPloginAdmin , 'urn:AGProjects:NGNPro', 0, ''); if (strlen($this->loginCredentials['customer_engine'])) { $this->customer_engine=$this->loginCredentials['customer_engine']; } else if (strlen($this->soapEngines[$this->sip_engine]['customer_engine'])) { $this->customer_engine=$this->soapEngines[$this->sip_engine]['customer_engine']; } else { $this->customer_engine=$this->sip_engine; } if (strlen($this->loginCredentials['voicemail_engine'])) { $this->voicemail_engine=$this->loginCredentials['voicemail_engine']; } else if (strlen($this->soapEngines[$this->sip_engine]['voicemail_engine'])) { $this->voicemail_engine=$this->soapEngines[$this->sip_engine]['voicemail_engine']; } else { $this->voicemail_engine=$this->sip_engine; } if (strlen($this->loginCredentials['enum_engine'])) { $this->enum_engine=$this->loginCredentials['enum_engine']; } else if (strlen($this->soapEngines[$this->sip_engine]['enum_engine'])) { $this->enum_engine=$this->soapEngines[$this->sip_engine]['enum_engine']; } else { $this->enum_engine=$this->sip_engine; } if (strlen($this->loginCredentials['rating_engine'])) { $this->rating_engine=$this->loginCredentials['rating_engine']; } else if (strlen($this->soapEngines[$this->sip_engine]['rating_engine'])) { $this->rating_engine=$this->soapEngines[$this->sip_engine]['rating_engine']; } else { $this->rating_engine=$this->sip_engine; } // overwrite default settings if (strlen($this->soapEngines[$this->sip_engine]['sip_proxy'])) { $this->sip_proxy = $this->soapEngines[$this->sip_engine]['sip_proxy']; } if (strlen($this->soapEngines[$this->sip_engine]['sip_outbound_proxy'])) { $this->sip_outbound_proxy = $this->soapEngines[$this->sip_engine]['sip_outbound_proxy']; } if (strlen($this->soapEngines[$this->sip_engine]['support_company'])) { $this->support_company = $this->soapEngines[$this->sip_engine]['support_company']; } if (strlen($this->soapEngines[$this->sip_engine]['support_web'])) { $this->support_web = $this->soapEngines[$this->sip_engine]['support_web']; } if (strlen($this->soapEngines[$this->sip_engine]['support_email'])) { $this->support_email = $this->soapEngines[$this->sip_engine]['support_email']; } if (strlen($this->soapEngines[$this->sip_engine]['billing_email'])) { $this->billing_email = $this->soapEngines[$this->sip_engine]['billing_email']; } if (strlen($this->soapEngines[$this->sip_engine]['sip_settings_page'])) { $this->sip_settings_page = $this->soapEngines[$this->sip_engine]['sip_settings_page']; } if (strlen($this->soapEngines[$this->sip_engine]['digest_settings_page'])) { $this->digest_settings_page = $this->soapEngines[$this->sip_engine]['digest_settings_page']; } if (strlen($this->soapEngines[$this->sip_engine]['xcap_root'])) { $this->xcap_root = $this->soapEngines[$this->sip_engine]['xcap_root']; } if (strlen($this->soapEngines[$this->sip_engine]['cdrtool_address'])) { $this->cdrtool_address = $this->soapEngines[$this->sip_engine]['cdrtool_address']; } if (strlen($this->soapEngines[$this->sip_engine]['msrp_relay'])) { $this->msrp_relay = $this->soapEngines[$this->sip_engine]['msrp_relay']; } if ($this->soapEngines[$this->sip_engine]['emergency_regions']) { $this->emergency_regions = $this->soapEngines[$this->sip_engine]['emergency_regions']; } if ($this->soapEngines[$this->sip_engine]['pstn_access']) { $this->pstn_access = $this->soapEngines[$this->sip_engine]['pstn_access']; } if ($this->soapEngines[$this->sip_engine]['call_limit']) { $this->platform_call_limit = $this->soapEngines[$this->sip_engine]['call_limit']; } if ($this->soapEngines[$this->sip_engine]['sms_access']) { $this->sms_access = $this->soapEngines[$this->sip_engine]['sms_access']; } if ($this->soapEngines[$this->sip_engine]['voicemail_server']) { $this->voicemail_server = $this->soapEngines[$this->sip_engine]['voicemail_server']; } if ($this->soapEngines[$this->sip_engine]['currency']) { $this->currency = $this->soapEngines[$this->sip_engine]['currency']; } if ($this->soapEngines[$this->sip_engine]['voicemail_access_number']) { $this->voicemail_access_number = $this->soapEngines[$this->sip_engine]['voicemail_access_number']; } if ($this->soapEngines[$this->sip_engine]['FUNC_access_number']) { $this->FUNC_access_number = $this->soapEngines[$this->sip_engine]['FUNC_access_number']; } if ($this->soapEngines[$this->sip_engine]['FNOA_access_number']) { $this->FNOA_access_number = $this->soapEngines[$this->sip_engine]['FNOA_access_number']; } if ($this->soapEngines[$this->sip_engine]['FBUS_access_number']) { $this->FBUS_access_number = $this->soapEngines[$this->sip_engine]['FBUS_access_number']; } if ($this->soapEngines[$this->sip_engine]['FNOL_access_number']) { $this->FNOL_access_number = $this->soapEngines[$this->sip_engine]['FNOL_access_number']; } if ($this->soapEngines[$this->sip_engine]['payment_processor_class']) { $this->payment_processor_class = $this->soapEngines[$this->sip_engine]['payment_processor_class']; } if ($this->soapEngines[$this->sip_engine]['change_privacy_access_number']) { $this->change_privacy_access_number = $this->soapEngines[$this->sip_engine]['change_privacy_access_number']; } if ($this->soapEngines[$this->sip_engine]['check_privacy_access_number']) { $this->check_privacy_access_number = $this->soapEngines[$this->sip_engine]['check_privacy_access_number']; } if ($this->soapEngines[$this->sip_engine]['reject_anonymous_access_number']) { $this->reject_anonymous_access_number = $this->soapEngines[$this->sip_engine]['reject_anonymous_access_number']; } if ($this->soapEngines[$this->sip_engine]['show_directory']) { $this->show_directory = $this->soapEngines[$this->sip_engine]['show_directory']; } if (isset($this->soapEngines[$this->sip_engine]['absolute_voicemail_uri'])) { $this->absolute_voicemail_uri = $this->soapEngines[$this->sip_engine]['absolute_voicemail_uri']; } if (isset($this->soapEngines[$this->sip_engine]['enable_thor'])) { $this->enable_thor=$this->soapEngines[$this->sip_engine]['enable_thor']; } if (isset($this->soapEngines[$this->sip_engine]['sip_accounts_lite'])) { $this->sip_accounts_lite=$this->soapEngines[$this->sip_engine]['sip_accounts_lite']; } if (strlen($this->soapEngines[$this->sip_engine]['timeout'])) { $this->soapTimeout=intval($this->soapEngines[$this->sip_engine]['timeout']); } if (strlen($this->soapEngines[$this->sip_engine]['store_clear_text_passwords'])) { $this->store_clear_text_passwords=$this->soapEngines[$this->sip_engine]['store_clear_text_passwords']; } if (isset($this->soapEngines[$this->sip_engine]['show_download_tab'])) { $this->show_download_tab=$this->soapEngines[$this->sip_engine]['show_download_tab']; } if (strlen($this->soapEngines[$this->sip_engine]['show_barring_tab'])) { $this->show_barring_tab=$this->soapEngines[$this->sip_engine]['show_barring_tab']; } if (isset($this->soapEngines[$this->sip_engine]['disable_extra_groups'])) { $this->disable_extra_groups=$this->soapEngines[$this->sip_engine]['disable_extra_groups']; } if (strlen($this->soapEngines[$this->sip_engine]['notify_on_sip_account_changes'])) { //dprint($this->soapEngines[$this->sip_engine]['notify_on_sip_account_changes']); $this->notify_on_sip_account_changes=$this->soapEngines[$this->sip_engine]['notify_on_sip_account_changes']; } if ($this->loginCredentials['templates_path']) { $this->templates_path = $this->loginCredentials['templates_path']; } else if ($this->soapEngines[$this->sip_engine]['templates_path']) { $this->templates_path = $this->soapEngines[$this->sip_engine]['templates_path']; } // Instantiate the SOAP clients // sip $this->SipPort = new $this->soapClassSipPort($this->SOAPurl); $this->SipPort->_options['timeout'] = $this->soapTimeout; $this->SipPort->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0); $this->SipPort->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0); if ($this->showSoapConnectionInfo) { printf ("

%s at %s as %s ",$this->soapClassSipPort,$this->SOAPurl,$this->SOAPurl,$this->soapUsername); } // voicemail $this->SOAPurlVoicemail = $this->soapEngines[$this->voicemail_engine]['url']; $this->SOAPloginVoicemail = array( "username" => $this->soapEngines[$this->voicemail_engine]['username'], "password" => $this->soapEngines[$this->voicemail_engine]['password'], "admin" => true, "impersonate" => intval($this->customer) ); $this->SoapAuthVoicemail = array('auth', $this->SOAPloginVoicemail , 'urn:AGProjects:NGNPro', 0, ''); $this->VoicemailPort = new $this->soapClassVoicemailPort($this->SOAPurlVoicemail); if (strlen($this->soapEngines[$this->voicemail_engine]['timeout'])) { $this->VoicemailPort->_options['timeout'] = intval($this->soapEngines[$this->voicemail_engine]['timeout']); } else { $this->VoicemailPort->_options['timeout'] = $this->soapTimeout; } $this->VoicemailPort->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0); $this->VoicemailPort->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0); if ($this->showSoapConnectionInfo && $this->SOAPurlVoicemail != $this->SOAPurl) { printf ("
%s at %s as %s ",$this->soapClassVoicemailPort,$this->SOAPurlVoicemail,$this->SOAPurlVoicemail,$this->soapEngines[$this->voicemail_engine]['username']); } // enum $this->SOAPurlEnum = $this->soapEngines[$this->enum_engine]['url']; $this->SOAPloginEnum = array( "username" => $this->soapEngines[$this->enum_engine]['username'], "password" => $this->soapEngines[$this->enum_engine]['password'], "admin" => true, "impersonate" => intval($this->customer) ); $this->SoapAuthEnum = array('auth', $this->SOAPloginEnum , 'urn:AGProjects:NGNPro', 0, ''); $this->EnumPort = new $this->soapClassEnumPort($this->SOAPurlEnum); if (strlen($this->soapEngines[$this->enum_engine]['timeout'])) { $this->EnumPort->_options['timeout'] = intval($this->soapEngines[$this->enum_engine]['timeout']); } else { $this->EnumPort->_options['timeout'] = $this->soapTimeout; } $this->EnumPort->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0); $this->EnumPort->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0); if ($this->showSoapConnectionInfo && $this->SOAPurlEnum != $this->SOAPurl) { printf ("
%s at %s as %s ",$this->soapClassEnumPort,$this->SOAPurlEnum,$this->SOAPurlEnum,$this->soapEngines[$this->enum_engine]['username']); } // rating $this->SOAPurlRating = $this->soapEngines[$this->rating_engine]['url']; $this->SOAPloginRating = array( "username" => $this->soapEngines[$this->rating_engine]['username'], "password" => $this->soapEngines[$this->rating_engine]['password'], "admin" => true, "impersonate" => intval($this->customer) ); $this->SoapAuthRating = array('auth', $this->SOAPloginRating , 'urn:AGProjects:NGNPro', 0, ''); $this->RatingPort = new $this->soapClassRatingPort($this->SOAPurlRating); if (strlen($this->soapEngines[$this->rating_engine]['timeout'])) { $this->RatingPort->_options['timeout'] = intval($this->soapEngines[$this->rating_engine]['timeout']); } else { $this->RatingPort->_options['timeout'] = $this->soapTimeout; } $this->RatingPort->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0); $this->RatingPort->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0); if ($this->showSoapConnectionInfo && $this->SOAPurlRating != $this->SOAPurl) { printf ("
%s at %s as %s ",$this->soapClassRatingPort,$this->SOAPurlRating,$this->SOAPurlRating,$this->soapEngines[$this->rating_engine]['username']); } // customer $this->SOAPurlCustomer = $this->soapEngines[$this->customer_engine]['url']; $this->SOAPloginCustomer = array( "username" => $this->soapEngines[$this->customer_engine]['username'], "password" => $this->soapEngines[$this->customer_engine]['password'], "admin" => true ); $this->SoapAuthCustomer = array('auth', $this->SOAPloginCustomer , 'urn:AGProjects:NGNPro', 0, ''); $this->CustomerPort = new $this->soapClassCustomerPort($this->SOAPurlCustomer); if (strlen($this->soapEngines[$this->customer_engine]['timeout'])) { $this->CustomerPort->_options['timeout'] = intval($this->soapEngines[$this->customer_engine]['timeout']); } else { $this->CustomerPort->_options['timeout'] = $this->soapTimeout; } $this->CustomerPort->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0); $this->CustomerPort->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0); if ($this->showSoapConnectionInfo && $this->SOAPurlCustomer != $this->SOAPurl) { printf ("
%s at %s as %s ",$this->soapClassCustomerPort,$this->SOAPurlCustomer,$this->SOAPurlCustomer,$this->soapEngines[$this->customer_engine]['username']); } } - function getMongoJournalTable() { - $this->mongo_table_ro = NULL; - $this->mongo_table_rw = NULL; - $this->mongo_exception = 'Mongo exception'; - - if (is_array($this->mongo_db)) { - $mongo_uri = $this->mongo_db['uri']; - $mongo_replicaSet = $this->mongo_db['replicaSet']; - $mongo_database = $this->mongo_db['database']; - $mongo_table = $this->mongo_db['table']; - try { - $mongo_connection = new Mongo("mongodb://$mongo_uri", array("replicaSet" => $mongo_replicaSet)); - $mongo_db = $mongo_connection->selectDB($mongo_database); - $this->mongo_table_ro = $mongo_db->selectCollection($mongo_table); - $this->mongo_table_ro->setSlaveOkay(true); - $this->mongo_table_rw = $mongo_db->selectCollection($mongo_table); - return true; - } catch (MongoException $e) { - $this->mongo_exception=$e->getMessage(); - return false; - } catch (MongoConnectionException $e) { - $this->mongo_exception=$e->getMessage(); - return false; - } catch (Exception $e) { - $this->mongo_exception=$e->getMessage(); - return false; - } - } - return false; - } - function getAccount($account) { dprint("getAccount($account, engine=$this->sip_engine)"); list($username,$domain)=explode("@",trim($account)); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getAccount(array("username" =>$username,"domain" =>$domain)); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } //print "

";
         dprint_r($result);
         $this->owner     = $result->owner;
 
         if (!is_array($result->properties))   $result->properties=array();
         if (!is_array($result->groups))       $result->groups=array();
 
         if (!$result->quota) $result->quota=0;
 
         foreach ($result->properties as $_property) {
             $this->Preferences[$_property->name]=$_property->value;
         }
 
         //dprint_r($this->Preferences);
 
         if (!$this->Preferences['language']) {
             $this->Preferences['language'] ='en';
         }
 
         if ( $this->Preferences['blocked_by'] && !in_array("blocked",$result->groups)) {
             $this->Preferences['blocked_by']='';
         }
 
         $this->username       = $result->id->username;
         $this->domain         = $result->id->domain;
         $this->password       = $result->password;
         $this->firstName      = $result->firstName;
         $this->lastName       = $result->lastName;
         $this->rpid           = $result->rpid;
         $this->owner          = $result->owner;
         $this->timezone       = $result->timezone;
         $this->email          = $result->email;
         $this->groups         = $result->groups;
         $this->createDate     = $result->createDate;
         $this->web_password   = $this->Preferences['web_password'];
         $this->quickdial      = $result->quickdialPrefix;
         $this->timeout        = intval($result->timeout);
         $this->quota          = $result->quota;
         $this->prepaid        = intval($result->prepaid);
         $this->region         = $result->region;
 
         $this->account        = $this->username."@".$this->domain;
         $this->fullName       = $this->firstName." ".$this->lastName;
         $this->name           = $this->firstName; // used by smarty
 
         $this->yuibikey         = $result->Preferences['yubikey'];
 
         if ($this->soapEngines[$this->sip_engine]['call_limit']) {
             if ($result->callLimit) {
                 $this->callLimit   = $result->callLimit;
             } else  {
                 $this->callLimit = '';
             }
         }
 
         if ($this->soapEngines[$this->sip_engine]['ip_access_list']) {
             if (is_array($result->acl) and count($result->acl)) {
                 foreach (array_keys($result->acl) as $key) {
                     $this->ip_access_list .= sprintf("%s/%s ",$result->acl[$key]->ip, $result->acl[$key]->mask);
                 }
                 $this->ip_access_list = trim($this->ip_access_list);
             } else  {
                 $this->ip_access_list = $this->soapEngines[$this->sip_engine]['ip_access_list'];
             }
         }
 
         $this->sipId=array("username" => $this->username,
                            "domain" => $this->domain
                            );
 
         if (!$this->timeout) {
             $this->timeoutWasNotSet=1;
             $this->timeout=intval($this->FNOA_timeoutDefault);
         }
 
         if ($this->timeout > 900 ) {
             $this->timeoutWasNotSet=1;
             $this->timeout=intval(900);
         }
 
         $this->getOwnerSettings($this->owner);
 
         $this->getDomainOwner($this->domain);
 
         $this->getMobileNumber();
 
         if ($this->append_domain_to_xcap_root) {
         	$this->xcap_root     = rtrim($this->xcap_root,'/')."@".$this->domain."/";
         }
 
         $this->result    = $result;
 
     }
 
     function showAccount() {
         dprint('showAccount()');
 
         if (!$this->account) {
             print "";
             print _("Error: SIP Account information cannot be retrieved. ");
             return 0;
             print "";
         }
 
         print "
         
         ";
 
         $this->showHeader();
 
         $this->chapterTableStart();
 
     	$this->showAboveTabs();
         $this->showTabs();
     	$this->showUnderTabs();
 
         $this->showTitleBar();
 
         if (!array_key_exists($this->tab,$this->tabs)) $this->tab="settings";
 
 
         // show tab
         $tabFunctionName='show'.ucfirst($this->tab).'Tab';
 
         $this->$tabFunctionName();
 
         $this->showFooter();
 
     	$this->chapterTableStop();
     }
 
     function getDomainOwner ($domain='') {
         dprint("getdomainOwner($domain)");
 
         if (!$domain) return;
         // Filter
         $filter=array('domain'    => $domain);
 
         // Range
         $range=array('start' => 0,
                      'count' => 1
                      );
 
         $orderBy = array('attribute' => 'changeDate',
                          'direction' => 'DESC'
                          );
 
         // Compose query
         $Query=array('filter'     => $filter,
                      'orderBy' => $orderBy,
                      'range'   => $range
                      );
 
         //dprint_r($Query);
 
         // Call function
         $this->SipPort->addHeader($this->SoapAuth);
         $result     = $this->SipPort->getDomains($Query);
 
         if ((new PEAR)->isError($result)) {
             $error_msg  = $result->getMessage();
             $error_fault= $result->getFault();
             $error_code = $result->getCode();
             printf ("

Error %s: %s (%s): %s",$this->SoapEngine->SOAPurl,$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { if ($result->domains[0]) { $this->reseller = $result->domains[0]->reseller; $this->customer = $result->domains[0]->customer; } } } function getMobileNumber() { //dprint('getMobileNumber()'); $this->mobile_number=''; if ($this->Preferences['mobile_number']) { $this->mobile_number=$this->Preferences['mobile_number']; } else if ($this->owner_information['mobile']) { $this->mobile_number=$this->owner_information['mobile']; } } function setLanguage() { dprint("setLanguage()"); if ($this->login_type == 'reseller' || $this->login_type == 'customer') { $lang = $this->ResellerLanguage; } else if ($this->login_type == 'subscriber') { if (!$this->Preferences['language']) { foreach (array_keys($this->languages) as $_lang) { if ($this->languages[$_lang]['timezone'] == $this->timezone) { $lang=$_lang; break; } } } $lang = $this->Preferences['language']; } else { $lang = "en"; } //print("Set language to $lang"); $this->changeLanguage($lang); } function getOwnerSettings($owner='') { dprint("getOwnerSettings($owner)"); if (!$owner) { return false; } $this->CustomerPort->addHeader($this->SoapAuthCustomer); $result = $this->CustomerPort->getAccount($owner); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (CustomerPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } $this->owner_information=array( "username" => $result->username, "password" => $result->password, "firstName" => $result->firstName, "lastName" => $result->lastName, "organization" => $result->organization, "timezone" => $result->timezone, "address" => $result->address, "billingAddress" => $result->billingAddress, "city" => $result->city, "state" => $result->state, "country" => $result->country, "postcode" => $result->postcode, "tel" => $result->tel, "enum" => $result->enum, "mobile" => $result->mobile, "fax" => $result->fax, "email" => $result->email, "web" => $result->web ); //dprint_r($this->owner_information); } function getAliases() { // Get Aliases dprint("getAliases()"); $this->aliases=array(); $this->SipPort->addHeader($this->SoapAuth); // Filter $filter=array('targetUsername' => $this->username, 'targetDomain' => $this->domain ); // Range $range=array('start' => 0, 'count' => 20 ); // Order $orderBy = array('attribute' => 'aliasUsername', 'direction' => 'ASC' ); // Compose query $Query=array('filter' => $filter, 'orderBy' => $orderBy, 'range' => $range ); // Call function $result = $this->SipPort->getAliases($Query); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } //dprint_r($result); foreach ($result->aliases as $_alias) { $this->aliases[]=$_alias->id->username.'@'.$_alias->id->domain; } } function getRatingEntityProfiles() { dprint("getRatingEntityProfiles()"); $this->EntityProfiles=array(); $this->RatingPort->addHeader($this->SoapAuthRating); $entity="subscriber://".$this->username."@".$this->domain; $result = $this->RatingPort->getEntityProfiles($entiry); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (RatingPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } $this->EntityProfiles=$result; } function setAliases() { dprint("setAliases()"); $aliases_new=$_REQUEST['aliases']; $this->getAliases(); $aliases_old=$this->aliases; $addAliases = array_unique(array_diff($aliases_new,$aliases_old)); $deleteAliases = array_unique(array_diff($aliases_old,$aliases_new)); foreach ($addAliases as $_alias) { $_alias=trim(strtolower($_alias)); if (!preg_match("/^[a-z0-9-_.@]+$/i",$_alias)) continue; $els=explode("@",$_alias); if (count($els) ==1 ) { $_alias_username=$_alias; $_alias_domain=$this->domain; } else if (count($els) ==2) { $_alias_username=$els[0]; $_alias_domain=$this->domain; } else { continue ; } $_aliasObject=array("id"=>array("username"=>strtolower($_alias_username), "domain"=>strtolower($_alias_domain) ), "owner"=>intval($this->owner), "target"=>$this->sipId ) ; $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->addAlias($_aliasObject); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } } foreach ($deleteAliases as $_alias) { $_alias=trim($_alias); if (!strlen($_alias)) continue; $els=explode("@",$_alias); if (count($els) ==1 ) { $_alias_username=$_alias; $_alias_domain=$this->domain; } else if (count($els) == 2) { $_alias_username=$els[0]; $_alias_domain=$els[1]; } else { continue ; } $_aliasObject=array("username"=>$_alias_username, "domain" =>$_alias_domain ); dprint_r($_aliasObject); dprint("deleteAlias"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->deleteAlias($_aliasObject); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } } unset($this->aliases); } function getVoicemail () { dprint("getVoicemail()"); $this->VoicemailPort->addHeader($this->SoapAuthVoicemail); $result = $this->VoicemailPort->getAccount($this->sipId); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); if ($error_fault->detail->exception->errorcode != "2000" && $error_fault->detail->exception->errorcode != "1010") { printf ("

Error (VoicemailPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { return true; } } if (!$result->mailbox) { dprint ("No voicemail account found"); return false; } $this->voicemail['Mailbox'] = $result->mailbox; $this->voicemail['Password'] = $result->password; $this->voicemail['Name'] = $result->name; $this->voicemail['Email'] = $result->email; $this->voicemail['Info'] = $result->info; $this->voicemail['Options'] = $result->options; $this->voicemail['Account'] = $result->mailbox.'@'.$this->voicemail_server; // used by template system $this->voicemailMailbox = $result->mailbox; //dprint_r($this->voicemail); return true; } function showTitleBar() { print "

"; printf (("%s <sip:%s@%s>"),$this->fullName,$this->username,$this->domain); print " "; if ($this->login_type == 'subscriber' && !$this->isEmbedded()) { print ""; print _("Logout"); print ""; } else { if ($this->enable_thor) { print " "; if ($this->isEmbedded()) { print " "; print _("Home Node"); } else { print ""; print _("SIP Thor Node"); print ""; } if ($this->homeNode=getSipThorHomeNode($this->account,$this->sip_proxy)) { printf (" %s",$this->homeNode); } else { print " "; print _("Unknown"); print ""; } } } print "
"; } function getDivertTargets () { dprint("getDivertTargets()"); $this->divertTargets[] = array("name" => _("No diversion"), "value" => "", "description" => "Disabled" ); if ($this->voicemail['Account']) { $vmf=$this->getVoicemailForwarding(); if (is_array($vmf)) { $this->divertTargets[]=$vmf; } } if ($this->owner) { if (in_array("free-pstn",$this->groups)) { if ($this->owner_information['tel']) { $tel = preg_replace("/[^\d+]/", "", $this->owner_information['tel']); $tel_enum = str_replace("+", "00", $tel); $telf = $tel_enum . "@" . $this->domain; if (!$seen[$tel_enum] && !in_array($tel_enum,$this->enums)) { $this->divertTargets[]=array("name" => sprintf (_("Tel %s"),$tel), "value" => $telf, "description" => "Tel"); } $seen[$tel_enum]++; } if ($this->owner_information['enum']) { $tel = preg_replace("/[^\d+]/", "", $this->owner_information['enum']); $tel_enum = str_replace("+", "00", $tel); $telf = $tel_enum . "@" . $this->domain; if (!$seen[$tel_enum] && !in_array($tel_enum,$this->enums)) { $this->divertTargets[]=array("name" => sprintf (_("Tel %s"),$tel), "value" => $telf, "description" => "ENUM"); } $seen[$tel_enum]++; } } } if ($this->mobile_number) { $tel = preg_replace("/[^\d+]/", "", $this->mobile_number); $tel_enum = str_replace("+", "00", $tel); $telf = $tel_enum . "@" . $this->domain; if (!$seen[$tel_enum] && !in_array($tel_enum,$this->enums)) { $this->divertTargets[] = array("name" => sprintf (_("Mobile %s"),$tel), "value" => $telf, "description" => "Mobile" ); } $seen[$tel_enum]++; } $this->divertTargets[]=array("name" => sprintf (_("Other")), "value" => "", "description" => "Other" ); //print_r($this->divertTargets); } function pstnChangesAllowed() { dprint("pstnChangesAllowed()"); if ($this->login_type == 'subscriber') { $this->pstn_changes_allowed = false; return; } else { if ($this->login_type == 'admin') { $this->pstn_changes_allowed = true; return; // for a reseller we need to check if a subaccount is allowed } else if ($this->loginCredentials['customer'] == $this->loginCredentials['reseller']) { if ($this->resellerProperties['pstn_changes']) { dprint("is reseller"); $this->pstn_changes_allowed = true; } return; } else if ($this->customerImpersonate == $this->loginCredentials['reseller']) { if ($this->resellerProperties['pstn_changes']) { dprint("impersonate reseller"); $this->pstn_changes_allowed = true; } return; } else if ($this->resellerProperties['pstn_changes'] && $this->customerProperties['pstn_changes']) { $this->pstn_changes_allowed = true; return; } } $this->pstn_changes_allowed = false; return; } function smsChangesAllowed() { dprint("smsChangesAllowed()"); if ($this->login_type == 'subscriber') { $this->sms_changes_allowed = false; return; } else { // for a reseller we need to check if a subaccount is allowed if ($this->loginCredentials['customer'] == $this->loginCredentials['reseller']) { if ($this->resellerProperties['sms_access']) { dprint("is reseller"); $this->sms_changes_allowed = true; } return; } else if ($this->customerImpersonate == $this->loginCredentials['reseller']) { if ($this->resellerProperties['sms_access']) { dprint("impersonate reseller"); $this->sms_changes_allowed = true; } return; } else if ($this->resellerProperties['sms_access'] && $this->customerProperties['sms_access']) { $this->sms_changes_allowed = true; return; } } $this->sms_changes_allowed = false; return; } function prepaidChangesAllowed() { dprint("prepaidChangesAllowed()"); if ($this->login_type == 'subscriber') { $this->prepaid_changes_allowed = false; return; } else { if ($this->login_type == 'admin') { $this->prepaid_changes_allowed = true; return; // for a reseller we need to check if a subaccount is allowed } else if ($this->loginCredentials['customer'] == $this->loginCredentials['reseller']) { dprint("is reseller"); if ($this->resellerProperties['prepaid_changes']) { $this->prepaid_changes_allowed = true; } return; } else if ($this->customerImpersonate == $this->loginCredentials['reseller']) { dprint("impersonate reseller"); if ($this->resellerProperties['prepaid_changes']) { $this->prepaid_changes_allowed = true; } return; } else if ($this->resellerProperties['prepaid_changes'] && $this->customerProperties['prepaid_changes']) { $this->prepaid_changes_allowed = true; return; } } $this->prepaid_changes_allowed = false; return; } function getCustomerSettings () { dprint("getCustomerSettings()"); if (!$this->loginCredentials['customer']) return; $id=$this->loginCredentials['customer']; $this->CustomerPort->addHeader($this->SoapAuthCustomer); $result = $this->CustomerPort->getAccount(intval($this->loginCredentials['customer'])); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (CustomerPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } foreach ($result->properties as $_property) { $this->customerProperties[$_property->name]=$_property->value; } $this->customerImpersonate=$result->impersonate; //dprint_r($this->customerProperties); } function getResellerSettings () { dprint("getResellerSettings()"); $this->logoFile = $this->getFileTemplate("logo","logo"); $this->headerFile = $this->getFileTemplate("header.phtml"); $this->footerFile = $this->getFileTemplate("footer.phtml"); $this->cssFile = $this->getFileTemplate("main.css"); if (!$this->reseller) { if ($this->pstn_access) { $this->availableGroups['free-pstn'] = array( "Group" => "free-pstn", "WEBName" => sprintf(_("PSTN Access")), "WEBComment" => sprintf(_("Caller-ID")), "SubscriberMayEditIt" => 0, "SubscriberMaySeeIt" => 1, "ResellerMayEditIt" => 1, "ResellerMaySeeIt" => 1 ); if ($this->change_privacy_access_number) { $_comment = sprintf(_("Dial %s to change"), $this->change_privacy_access_number); } else { $_comment = ''; } $this->availableGroups['anonymous'] = array( "Group" => "anonymous", "WEBName" => sprintf (_("PSTN Privacy")), "WEBComment" => $_comment, "SubscriberMaySeeIt" => 1, "SubscriberMayEditIt" => 1, "ResellerMayEditIt" => 1, "ResellerMaySeeIt" => 1 ); if ($this->pstn_access) { $this->availableGroups['rate-on-net'] = array("Group"=>"rate-on-net", "WEBName" =>sprintf(_("Rate on net")), "SubscriberMayEditIt"=>0, "SubscriberMaySeeIt"=>0, "ResellerMayEditIt"=>1, "ResellerMaySeeIt"=>1 ); if ($this->sms_access) { $this->availableGroups['sms'] = array("Group"=>"sms", "WEBName" =>sprintf(_("Mobile SMS")), "SubscriberMayEditIt"=>0, "SubscriberMaySeeIt"=>1, "ResellerMayEditIt"=>0, "ResellerMaySeeIt"=>1 ); } } if ($this->require_proof_of_identity) { $this->availableGroups['payments'] = array("Group"=>"payments", "WEBName" =>sprintf(_("CC Payments")), "SubscriberMayEditIt"=>0, "SubscriberMaySeeIt"=>0, "ResellerMayEditIt"=>1, "ResellerMaySeeIt"=>1 ); } } return true; } $this->CustomerPort->addHeader($this->SoapAuthCustomer); $result = $this->CustomerPort->getAccount(intval($this->reseller)); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (CustomerPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } foreach ($result->properties as $_property) { $this->resellerProperties[$_property->name]=$_property->value; } $this->resellerProperties['language'] = $result->language; $this->resellerProperties['timezone'] = $result->timezone; // overwrite settings from soap engine if ($this->resellerProperties['sip_proxy']) { $this->sip_proxy = $this->resellerProperties['sip_proxy']; } if ($this->resellerProperties['sip_outbound_proxy']) { $this->sip_outbound_proxy = $this->resellerProperties['sip_outbound_proxy']; } if ($this->resellerProperties['push_notifications_server']) { $this->sip_mobile_outbound_proxy = $this->resellerProperties['push_notifications_server']; } if (!$this->sip_outbound_proxy) { $this->sip_outbound_proxy = $this->sip_proxy; } if (!$this->sip_mobile_outbound_proxy) { $this->sip_mobile_outbound_proxy = $this->sip_outbound_proxy; } if ($this->resellerProperties['store_clear_text_passwords']) { $this->store_clear_text_passwords = $this->resellerProperties['store_clear_text_passwords']; } if ($this->resellerProperties['support_company']) { $this->support_company = $this->resellerProperties['support_company']; } if ($this->resellerProperties['support_web']) { $this->support_web = $this->resellerProperties['support_web']; } if ($this->resellerProperties['support_email']) { $this->support_email = $this->resellerProperties['support_email']; } if ($this->resellerProperties['billing_email']) { $this->billing_email = $this->resellerProperties['billing_email']; } if (!$this->billing_email) { $this->billing_email=$this->support_email; } if ($this->resellerProperties['sip_settings_page']) { $this->sip_settings_page = $this->resellerProperties['sip_settings_page']; } if ($this->resellerProperties['digest_settings_page']) { $this->digest_settings_page = $this->resellerProperties['digest_settings_page']; } if ($this->resellerProperties['xcap_root']) { $this->xcap_root = rtrim($this->resellerProperties['xcap_root'],'/'); if ($this->append_domain_to_xcap_root) { $this->xcap_root .= "@".$this->domain."/"; } } if ($this->resellerProperties['cdrtool_address']) { $this->cdrtool_address = $this->resellerProperties['cdrtool_address']; } if ($this->resellerProperties['msrp_relay']) { $this->msrp_relay = $this->resellerProperties['msrp_relay']; } if (isset($this->resellerProperties['voicemail_server'])) { $this->voicemail_server = $this->resellerProperties['voicemail_server']; } if (isset($this->resellerProperties['voicemail_access_number'])) { $this->voicemail_access_number = $this->resellerProperties['voicemail_access_number']; } if (isset($this->resellerProperties['currency'])) { $this->currency = $this->resellerProperties['currency']; } if (isset($this->resellerProperties['FUNC_access_number'])) { $this->FUNC_access_number = $this->resellerProperties['FUNC_access_number']; } if (isset($this->resellerProperties['FNOA_access_number'])) { $this->FNOA_access_number = $this->resellerProperties['FNOA_access_number']; } if (isset($this->resellerProperties['FBUS_access_number'])) { $this->FBUS_access_number = $this->resellerProperties['FBUS_access_number']; } if (isset($this->resellerProperties['FNOL_access_number'])) { $this->FNOL_access_number = $this->resellerProperties['FNOL_access_number']; } if (isset($this->resellerProperties['payment_processor_class'])) { $this->payment_processor_class = $this->resellerProperties['payment_processor_class']; } if (isset($this->resellerProperties['change_privacy_access_number'])) { $this->change_privacy_access_number = $this->resellerProperties['change_privacy_access_number']; } if (isset($this->resellerProperties['check_privacy_access_number'])) { $this->check_privacy_access_number = $this->resellerProperties['check_privacy_access_number']; } if (isset($this->resellerProperties['reject_anonymous_access_number'])) { $this->reject_anonymous_access_number = $this->resellerProperties['reject_anonymous_access_number']; } if (isset($this->resellerProperties['absolute_voicemail_uri'])) { $this->absolute_voicemail_uri = $this->resellerProperties['absolute_voicemail_uri']; } if (isset($this->resellerProperties['pstn_access'])) { $this->pstn_access = $this->resellerProperties['pstn_access']; } if (isset($this->resellerProperties['sms_access'])) { $this->sms_access = $this->resellerProperties['sms_access']; } if ($this->pstn_access) { $this->availableGroups['free-pstn'] = array("Group"=>"free-pstn", "WEBName" => sprintf(_("PSTN Access")), "WEBComment"=> sprintf(_("Caller-ID")), "SubscriberMayEditIt" => "0", "SubscriberMaySeeIt" => 1, "ResellerMayEditIt"=>1, "ResellerMaySeeIt"=>1 ); if ($this->change_privacy_access_number) { $_comment = sprintf(_("Dial %s to change"), $this->change_privacy_access_number); } else { $_comment = ''; } $this->availableGroups['anonymous'] = array( "Group" => "anonymous", "WEBName" => sprintf (_("PSTN Privacy")), "WEBComment" => $_comment, "SubscriberMaySeeIt" => 1, "SubscriberMayEditIt" => 1, "ResellerMayEditIt" => 1, "ResellerMaySeeIt" => 1 ); $this->availableGroups['rate-on-net'] = array( "Group" => "rate-on-net", "WEBName" => sprintf(_("Rate on net")), "SubscriberMayEditIt" => 0, "SubscriberMaySeeIt" => 0, "ResellerMayEditIt" => 1, "ResellerMaySeeIt" => 1 ); if ($this->sms_access) { $this->availableGroups['sms'] = array("Group"=>"sms", "WEBName" =>sprintf(_("Mobile SMS")), "SubscriberMayEditIt"=>0, "SubscriberMaySeeIt"=>1, "ResellerMayEditIt"=>0, "ResellerMaySeeIt"=>1 ); } } } function getDiversions() { dprint("getDiversions()"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getCallDiversions($this->sipId); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } //print_r($result); reset($this->diversionType); foreach(array_keys($this->diversionType) as $condition) { $uri=$result->$condition; if (($uri == "" || $uri == "voice-mailbox") && $this->absolute_voicemail_uri) { $uri = $this->voicemail['Account']; } else if ($uri == "voice-mailbox") { $uri = ""; } if (preg_match("/^(sip:|sips:)(.*)$/i",$uri,$m)) { $uri=$m[2]; } $this->diversions[$condition]=$uri; } //print_r($this->diversions); } function getDeviceLocations() { dprint("getDeviceLocations()"); require_once($this->SipUAImagesFile); $this->userAgentImages = $userAgentImages; $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getSipDeviceLocations(array($this->sipId)); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { foreach ($result[0]->locations as $locationStructure) { $contact=$locationStructure->address.":".$locationStructure->port; if ($locationStructure->publicAddress) { $publicContact=$locationStructure->publicAddress.":".$locationStructure->publicPort; } else { $publicContact=$contact; } $this->locations[]=array("contact" => $contact, "publicContact" => $publicContact, "expires" => $locationStructure->expires, "user_agent" => $locationStructure->userAgent, "transport" => $locationStructure->transport ); } } } function getVoicemailForwarding () { dprint("getVoicemailForwarding()"); if (!$this->voicemail['Account']) { return; } if ($this->absolute_voicemail_uri) { $value=$this->voicemail['Account']; } else { $value=""; } return array("name" => sprintf (_("Voice Mailbox")), "value" => $value, "description" => "Voicemail"); } function showAboveTabs() { print "

"; print "
"; } function showTabs() { print "
"; if ($this->isEmbedded()) { print $this->embedded_img;; } print "
    "; $items=0; while (list($k,$v)= each($this->tabs)) { if ($this->tab==$k) { $_class='active selected_tab'; } else { $_class='tabs'; } print "
  • $v
  • "; } print "
"; print "
"; } function showUnderTabs() { print "
"; print "
"; } function addInvoice($cardProcessor) { // called after CC payment sucessfull } function showPaymentsTab() { if (!$this->show_payments_tab) { return false; } if ($this->login_type == 'subscriber' && in_array("blocked",$this->groups)) { return false; } if ($_REQUEST['task'] == 'showprices') { $chapter=sprintf(_("Price list")); $this->showChapter($chapter); include($this->pstn_termination_price_page); return true; } $chapter=sprintf(_("Payments")); $this->showChapter($chapter); if (!$this->owner) { print "

"; print _("You must set the Owner to enable Credit Card Payments. "); print " "; return false; } $this->getBalanceHistory(); $today_summary = $this->getTodayBalanceSummary(); if ($today_summary['credit'] >= $this->max_credit_per_day) { print " "; if ($account->login_type!='subscriber') { print "

"; printf ("Daily Credit Exceeded"); } else { print _("Page Not Available"); $log=sprintf("CC transaction is not allowed from %s for %s (%s)",$_SERVER['REMOTE_ADDR'],$account->account,$this->fraud_reason); syslog(LOG_NOTICE, $log); } print " "; return false; } if (!count($this->balance_history)) { $this->first_transaction=true; } else { $this->first_transaction=false; } print " "; print "

"; printf (_("Calling to telephone numbers is possible at the costs set forth in the Price List. "),$this->url); //printf (_("You can purchase credit with a Credit Card or Bitcoin. "),$this->url, $this->url); //print "

"; //printf (_("You can purchase credit using Bitcoin. "), $this->url); print "

"; print " "; $credit_amount = 20; //$method = 'btc'; if ($method == 'btc') { print "

Select an amount and click submit to go the Bitcoin payment page."; printf("

Amount USD

", $this->account); } else { $chapter=sprintf(_("Credit Card")); $this->showChapter($chapter); if ($this->require_proof_of_identity) { if ($this->login_type == 'subscriber') { if (!in_array("payments",$this->groups)) { $this->showIdentityProof(); } } else { $this->showIdentityProof(); } if (!in_array("payments",$this->groups)) { return false; } } $payment_processor = new $this->payment_processor_class($this); if ($payment_processor->fraudDetected()) { $chapter=sprintf(_("Payments")); $this->showChapter($chapter); print " "; if ($account->login_type!='subscriber') { print "

"; printf ("%s",$this->fraud_reason); } else { print _("Page Not Available"); $log=sprintf("CC transaction is not allowed from %s for %s (%s)",$_SERVER['REMOTE_ADDR'],$account->account,$this->fraud_reason); syslog(LOG_NOTICE, $log); } print " "; return false; } $basket = array('pstn_credit'=>array('price' => $credit_amount, 'description' => _('Prepaid Credit'), 'unit' => 'credit', 'duration' => 'N/A', 'qty' => 1 ) ); // print "

";
            // print_r($payment_processor);
            // print "
"; $payment_processor->doDirectPayment($basket); //print "
";
             //
             //print_r($payment_processor);
             //print "
"; if ($payment_processor->transaction_results['success']) { // add PSTN credit $this->addBalanceReseller($credit_amount,sprintf("CC transaction %s",$payment_processor->transaction_results['id'])); } if ($this->first_transaction && $payment_processor->make_credit_checks) { // block account temporary to check the user // $transaction_data= $payment_processor->['CardProcessor']['transaction_data']; // if ( $this->email != $transaction_data['USER_EMAIL'] || // $this-> $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->removeFromGroup(array("username" => $this->username,"domain"=> $this->domain),"free-pstn"); } } } function showIdentityProof () { $max_file_size=1024000; $this->db = new DB_CDRTool(); $chapter=sprintf(_("Proof of Identity")); $this->showChapter($chapter); if ($_REQUEST['task'] == 'upload') { if (!$_FILES['tmpfile']['tmp_name']) { print ""; printf (_("Error: Please specify a file")); print ""; } else if (!$_REQUEST['name']) { print ""; printf (_("Error: Please enter the name printed on the Credit Card")); print ""; } else if (!preg_match("/^\d{4}$/",$_REQUEST['last_digits'])) { print ""; printf (_("Error: Last digits must be numeric")); print ""; } else if (!preg_match("/^\+[1-9][0-9]{7,14}$/",$_REQUEST['mobile_number'])) { print ""; printf (_("Error: Mobile Number must be in international format starting with +")); print ""; } else if ($_FILES['tmpfile']['size']['size'] > $max_file_size) { print ""; printf (_("Error: Maximum file size is %s"),$max_file_size); print ""; } else { $fp=fopen($_FILES['tmpfile']['tmp_name'], "r"); $content=fread($fp, $_FILES['tmpfile']['size']); fclose($fp); $query=sprintf("insert into subscriber_docs ( `name`, `username`, `domain`, `document`, `file_content`, `file_name`, `file_size`, `file_type`, `file_date`, `last_digits`, `mobile_number` ) values ( '%s', '%s', '%s', 'identity', '%s', '%s', '%s', '%s', NOW(), '%s', '%s' )", addslashes($_REQUEST['name']), addslashes($this->username), addslashes($this->domain), addslashes($content), addslashes($_FILES['tmpfile']['name']), addslashes($_FILES['tmpfile']['size']), addslashes($_FILES['tmpfile']['type']), addslashes($_REQUEST['last_digits']), addslashes($_REQUEST['mobile_number']) ); if (!$this->db->query($query)) { print ""; printf ("Error: Failed to save identity document %s (%s)", $this->db->Error,$this->db->Errno); print ""; } // send mail include_once('Mail.php'); include_once('Mail/mime.php'); $subject=sprintf ("%s requested CC Payments",$this->account); $hdrs = array( 'From' => $this->email, 'Subject' => $subject ); $crlf = "\n"; $mime = new Mail_mime($crlf); $mime->setTXTBody($subject); $mime->setHTMLBody($subject); $mime->addAttachment($content, $_FILES['tmpfile']['type'],$_FILES['tmpfile']['name'],'false'); $body = $mime->get(); $hdrs = $mime->headers($hdrs); $mail =& Mail::factory('mail'); $mail->send($this->billing_email, $hdrs, $body); } } if ($this->login_type != 'subscriber' && $_REQUEST['task'] == 'delete_identity_proof' && $_REQUEST['confirm']) { $query=sprintf("delete from subscriber_docs where username = '%s' and domain = '%s' and document = 'identity'", addslashes($this->username), addslashes($this->domain) ); if (!$this->db->query($query)) { print ""; printf ("Error deleting record: %s (%s)", $this->db->Error,$this->db->Errno); print ""; } } $query=sprintf("select * from subscriber_docs where username = '%s' and domain = '%s' and document = 'identity'", addslashes($this->username), addslashes($this->domain) ); if (!$this->db->query($query)) { print ""; printf ("Error for database query: %s (%s)", $this->db->Error,$this->db->Errno); print ""; } if ($this->db->num_rows()) { print "
"; if (!in_array("payments",$this->groups)) { print "

"; print _("Credit Card payments will be activated after your identity is verified. "); } printf ("

", _("Name"), _("Document"), _("Type"), _("Size"), _("Date"), _("Last digits"), _("Mobile Number") ); if ($this->login_type != 'subscriber') { print ""; } printf (""); $this->db->next_record(); $download_url=$this->url.'&action=export_identity_proof'; printf ("", $this->db->f('name'), $download_url, $this->db->f('file_name'), $this->db->f('file_type'), number_format($this->db->f('file_size')/1024,2), $this->db->f('file_date'), $this->db->f('last_digits'), $this->db->f('mobile_number') ); if ($this->login_type != 'subscriber') { if ($_REQUEST['task'] == 'delete_identity_proof' && !$_REQUEST['confirm']){ $delete_url=$this->url.'&tab=payments&task=delete_identity_proof&confirm=1'; printf ("",$delete_url,_("Confirm")); } else { $delete_url=$this->url.'&tab=payments&task=delete_identity_proof'; printf ("",$delete_url,$this->delete_img); } } printf (""); print "
%s%s%s%s%s%s%s"; print _("Actions"); print "
%s%s %s %s KB %s%s%s%s%s
"; } else { print "
"; print "

"; print _("Credit Card payments are available only to verified customers. "); print "

"; printf (_("To become verified, upload a copy of your passport or driving license that matches the Credit Card owner. "),$this->billing_email, $this->account, $this->billing_email); print "

"; printf (_("This copy will be kept on your profile until the credit card transaction has been approved. ")); print " "; print "

url method='post' enctype='multipart/form-data'> "; print " "; print " "; print " "; if (in_array("free-pstn",$this->groups)) { print " "; } print " "; print "
"; print _("Name printed on the Credit Card"); print " "; printf ("",$_REQUEST['name']); print "
"; print _("Scanned copy of your Passport or Driver License"); print " "; printf (""); print "
"; print _("Mobile Number"); print " "; printf(" %s",$_REQUEST['mobile_number'],_("International format starting with +")); print "
"; print _("Last 4 digits on your Credit Card"); print " "; printf("",$_REQUEST['last_digits']); print "
"; print "
"; } } function exportIdentityProof() { $this->db = new DB_CDRTool(); $query=sprintf("select * from subscriber_docs where username = '%s' and domain = '%s' and document = 'identity'", addslashes($this->username), addslashes($this->domain) ); if (!$this->db->query($query)) { print ""; printf ("Error for database query: %s (%s)", $this->db->Error,$this->db->Errno); print ""; } if ($this->db->num_rows()) { $this->db->next_record(); $h=sprintf("Content-type: %s",$this->db->f('file_type')); Header($h); $h=sprintf("Content-Disposition: attachment; filename=%s",$this->db->f('file_name')); Header($h); $h=sprintf("Content-Length: %s",$this->db->f('file_size')); Header($h); $this->db->p('file_content'); } } function showIdentityTab() { $this->getEnumMappings(); $this->getAliases(); $chapter=sprintf(_("SIP Account")); $this->showChapter($chapter); print "
"; /* print " "; */ print " "; print " "; print " "; if ($this->xcap_root && !in_array("trunking", $this->groups)) { print " "; } print "
"; print _("SIP Address"); print " sip:$this->account
"; print _("Full Name"); print " $this->fullName
"; print _("Username"); print " $this->username
"; print _("Domain/Realm"); print " $this->domain
"; print _("Outbound Proxy"); print " $this->sip_outbound_proxy
"; print _("XCAP Root"); print " $this->xcap_root
"; if ($this->pstn_access && $this->rpid) { $chapter=sprintf(_("PSTN")); $this->showChapter($chapter); print "
"; $t=0; foreach($this->enums as $e) { $t++; $rr=floor($t/2); $mod=$t-$rr*2; if ($mod ==0) { $_class='odd'; } else { $_class='even'; } print " "; } print "
"; print _("Caller-ID"); print " $this->rpid
"; print _("Phone Number"); print " $e
"; } if (!in_array("trunking",$this->groups)) { $chapter=sprintf(_("Aliases")); $this->showChapter($chapter); print "
"; printf (_("You may create new aliases for incoming calls")); printf ("
"); $t=0; print "
"; foreach($this->aliases as $a) { $t++; $rr=floor($t/2); $mod=$t-$rr*2; if ($mod ==0) { $_class='even'; } else { $_class='odd'; } print "
"; } print "
"; print "
"; print '
'; print $this->hiddenElements; print "
"; } if (!$this->isEmbedded() && $this->show_tls_section) { if ($this->enrollment_url) { include($this->enrollment_configuration); if (is_array($enrollment)) { $chapter=sprintf(_("TLS Certificate")); $this->showChapter($chapter); print " "; print _("X.509 Format"); printf (" Certificate ",$this->url); /* print " "; print _("PKCS#12 store format"); printf (" Certificate ",$this->url); */ } } } print "
"; print "
"; if ($this->email) { printf (_("Email SIP Account information to %s"),$this->email); print " "; } if ($this->sip_settings_page && $this->login_type != 'subscriber') { print "

"; printf (_("Login using SIP credentials at %s"),$this->sip_settings_page,$this->sip_settings_page); print "

"; } print $this->hiddenElements; print "
"; if($this->sip_settings_page) { $this->getbalancehistory(); if (count($this->balance_history) == "0" || $this->login_type != 'subscriber') { print "

"; print ""; $date1= new datetime($this->Preferences['account_delete_request']); $today= new datetime('now'); if ($this->Preferences['account_delete_request'] && $this->login_type != 'subscriber' ) { print "

User made a deletion request on: "; print $this->Preferences['account_delete_request']; print "

"; } if ($date1->diff($today)->d >= '2' || $this->Preferences['account_delete_request'] == '' || $this->login_type != 'subscriber' ) { print '

"; } print $this->hiddenElements; print "
"; } } function showDownloadTab() { if (in_array("trunking",$this->groups)) { return false; } $chapter=sprintf(_("SIP Client download")); $this->showChapter($chapter); print " "; $this->render_download_applet(); print " "; } function showDIDTab() { if (class_exists($this->did_processor_class)) { $did_processor = new $this->did_processor_class(); } if (!$_REQUEST['ddi_action']) { $chapter=sprintf(_("Registered Numbers")); $this->showChapter($chapter); print " "; $numbers=$did_processor->getOrders($this->account); if (count($numbers)) { print ""; printf (""); foreach (array_keys($numbers) as $_number) { $t++; $rr=floor($t/2); $mod=$t-$rr*2; if ($mod ==0) { $_class='odd'; } else { $_class='even'; } $form=sprintf(" "; $form.=$this->hiddenElements; $form.=sprintf ("",$_number); $form.=sprintf (""); $form.=sprintf (""); printf ("",$_number,$numbers[$_number]['country_name'],$numbers[$_number]['did_expire_date_gmt'],$numbers[$_number]['order_id'],$form); } print "
NumberCountryExpire DateOrderAction
+%s%s%s%s
%s
"; } print " "; } if ($prefixes = $did_processor->getPrefixes()) { if ($_REQUEST['ddi_action'] == 'register' && $_REQUEST['prefix'] && $_REQUEST['period']) { $chapter=sprintf(_("Register New Number")); $this->showChapter($chapter); print " "; $total=$prefixes[$_REQUEST['prefix']]['setup']+$prefixes[$_REQUEST['prefix']]['monthly']* $_REQUEST['period']; $basket = array('ddi_number' => array('price' => sprintf("%.2f",$total), 'description' => sprintf(_('Telephone Number (+%s %s) for %d months'),$_REQUEST['prefix'],$prefixes[$_REQUEST['prefix']]['country_name'],$_REQUEST['period']), 'unit' => 'number', 'duration' => 'N/A', 'qty' => 1 ) ); $this->hiddenElements=sprintf(" ", $_REQUEST['prefix'], $_REQUEST['period'] ); $data=array('customer_id' => $this->owner, 'country_iso' => $prefixes[$_REQUEST['prefix']]['country_iso'], 'city_prefix' => $prefixes[$_REQUEST['prefix']]['city_prefix'], 'period' => $_REQUEST['period'], 'map_data' => array( 'map_type' => 'URI', 'map_proto' => 'SIP', 'map_detail' => $this->account, 'map_pref_server' => 1 ), 'prepaid_funds' => "0", 'uniq_hash' => md5(mt_rand()) ); $did_processor->createOrder($data); /* if (class_exists($this->payment_processor_class)) { $payment_processor = new $this->payment_processor_class($this,$basket); } if ($payment_processor->transaction_results['success']) { if ($did_processor->createOrder($data)) { // add ENUM entry } else { // notify admin about payment without service fullfilment } } */ print " "; } else if ($_REQUEST['ddi_action'] == 'Renew' && $_REQUEST['number'] && $_REQUEST['period']) { $chapter=sprintf(_("Renew Number")); $this->showChapter($chapter); print " "; $data=array('customer_id' => $this->owner, 'did_number' => $_REQUEST['number'], 'period' => $_REQUEST['period'], 'uniq_hash' => md5(mt_rand()) ); print "Renewing number...."; $did_processor->renewOrder($data); print " "; } else if ($_REQUEST['ddi_action'] == 'Drop' && $_REQUEST['number']) { $chapter=sprintf(_("Cancel Number")); $this->showChapter($chapter); print " "; $data=array('customer_id' => $this->owner, 'did_number' => $_REQUEST['number'] ); $did_processor->cancelOrder($data); print " "; } else { $chapter=sprintf(_("Register New Number")); $this->showChapter($chapter); print " "; print "
"; print _("Select a region where you want to have a telephone number: "); print "

"; print ""; print "

"; print _("Select the duration for which you want to use the telephone number: "); print "

"; print ""; print $this->hiddenElements; print "

"; print ""; print ""; print "

"; } print " "; } else { print "

Error fetching DDI prefixes"; } print " "; } function showSupportTab() { $chapter=sprintf(_("Support")); $this->showChapter($chapter); print " "; print "

"; printf (_("To request support you may send an e-mail to %s"),$this->support_email); if ($this->support_web) { print "

"; printf (_("For more information visit %s"),$this->support_web); } print " "; } function render_download_applet() { $this->valid_os=array('nt','mac'); require("browser.php"); $os=browser_detection('os'); if ($this->create_certificate) { if ($_passport = $this->generateCertificate()) { $_account['passport'] = $_passport; } } $_account['sip_address'] = $this->account; $_account['display_name'] = sprintf("%s %s",$this->firstName,$this->lastName); $_account['password'] = $this->password; $_account['web_password'] = $this->Preferences['web_password']; $_account['email'] = $this->email; $_account['settings_url'] = $this->digest_settings_page; $_account['xcap_root'] = $this->xcap_root; $_account['outbound_proxy'] = $this->sip_proxy; if ($this->enrollment_url) { include($this->enrollment_configuration); if (is_array($enrollment)) { $_account['msrp_relay'] = $enrollment['msrp_relay']; $_account['conference_server'] = $enrollment['conference_server']; $_account['settings_url'] = $enrollment['settings_url']; if ($enrollment['ldap_hostname']) { $_account['ldap_hostname'] = $enrollment['ldap_hostname']; } if ($enrollment['ldap_dn']) { $_account['ldap_dn'] = $enrollment['ldap_dn']; } } } if ($this->store_clear_text_passwords=='false') { $match_password=false; if ($_REQUEST['password']) { $str=$this->result->id->username.":".$this->result->id->domain.":".$_REQUEST['password']; if (md5($str) == $this->result->ha1) { $_account['password']=$_REQUEST['password']; $match_password=true; } } if (!$match_password){ print "

"; print _("Please enter your SIP account password: "); if ($_REQUEST['password'] || $_REQUEST['continue']) { print "

"; } else { print "

"; } print ""; print "
"; print ""; if ($_REQUEST['password'] || $_REQUEST['continue']) { print "Entered password does not match your account"; } print "
"; print ""; print "
"; print ""; print ""; print "
"; $class='hide'; } } print "
"; if (in_array($os,$this->valid_os)) { print ""; print ""; } else { print ""; } print ""; print ""; print "
"; printf (_("Download and install %s preconfigured with your SIP account:"), $this->blink_download_url, $this->show_download_tab); print "
"; printf (" ", rand(), $this->blink_download_url, rawurlencode(json_encode($_account)) ); print "
"; print "

"; printf (_("To download %s visit %s"),$this->show_download_tab, $this->blink_download_url, $this->blink_download_url); print "

"; printf (_("If you have already installed %s, you can configure it to use your SIP account:"), $this->show_download_tab); print "
"; printf (" ", rand(), $this->show_download_tab, urlencode(json_encode($_account)) ); print "
"; print "

"; printf ("Notes. "); print _("Java Runtime Environment (JRE) must be activated in the web browser. "); print "

"; } function showFooter() { print "
"; if ($this->footerFile) { include ("$this->footerFile"); } else { print ""; } print "
"; } function showSettingsTab() { $use_yubikey=0; /* if (stream_resolve_include_path('Auth/Yubico.php')) { require_once 'Auth/Yubico.php'; $use_yubikey=1; } */ $this->getVoicemail(); print "
"; $chapter=sprintf(_("SIP Account")); $this->showChapter($chapter); if ($this->login_type != "subscriber" ) { print "
"; print "
firstName\">"; print "
"; print "
"; print "lastName\">"; print "
"; } print "
"; if ($this->login_type == 'subscriber' && in_array("deny-password-change",$this->groups)) { print _("Password can be changed only by the operator"); } else { print '"; printf ("\n\n\n\n",$this->password); } print "
"; print "
"; print '"; // print ''; print ' '; //print _("Enter text to change the password to access this web page"); print "
"; if ($use_yubikey == 1 && !$this->isEmbedded()) { print "
"; print "Yubikey id to allow SIP Account + Yubikey login to access this webpage.

The Yubikey id is the first 12 digits of the string generated by the key.

It can be set by clicking in this text field and pressing your Yubikey."); printf ("\"name=yubikey value=\"%s\">",$this->Preferences['yubikey']) ; print _("Enter Yubikey id"); print "
"; //print '
';
             //print($this->Preferences['yubikey']);
             //print_r($this);
             //print '
'; } print "
"; print "
"; print "
"; $this->showTimezones('timezone',$this->timezone); print " "; $timestamp=time(); $LocalTime=getLocalTime($this->timezone,$timestamp); print ""; print _("Local Time"); print ": $LocalTime"; //dprint_r($this->availableGroups); print "
"; if (count($this->emergency_regions) > 0) { print "
"; print ""; print "
"; } if ($this->pstn_access) { if (in_array("free-pstn",$this->groups)) { if (in_array("quota",$this->groups)) { $_class="alert alert-error"; } else { $_class=""; } if ($this->pstn_changes_allowed) { print "
"; printf ("%s
",$this->currency,$this->quota); //print "
"; if ($this->quota || in_array("quota",$this->groups)) { $this->getCallStatistics(); if ($this->thisMonth['price']) { printf (_("This month usage: %.2f %s"),$this->thisMonth['price'], $this->currency); printf (" / %d ",$this->thisMonth['calls']); print _("Calls "); } } print " "; if ($this->pstn_changes_allowed) { print ""; } print "
"; } else if ($this->quota) { print "
"; printf ("%s %s ",$this->quota,$this->currency); $this->getCallStatistics(); if ($this->thisMonth['price']) { printf (_("This month usage: %.2f %s"),$this->thisMonth['price'], $this->currency); printf (" / %d ",$this->thisMonth['calls']); print _("Calls"); } print "
"; } } if ($this->prepaid) $checked_box_prepaid="checked"; if (!$this->prepaid_changes_allowed) $disabled_box_prepaid = "disabled=true"; print "
"; } foreach (array_keys($this->availableGroups) as $key) { unset($disabled_box); if ($this->login_type == 'subscriber' && !$this->availableGroups[$key]['SubscriberMaySeeIt']) { continue; } if ($this->login_type == 'reseller' && !$this->availableGroups[$key]['ResellerMaySeeIt']) { continue; } if (in_array($key,$this->groups)) { $checked_box[$key]="checked"; } $elementName = $this->availableGroups[$key]["WEBName"]; $elementComment = $this->availableGroups[$key]["WEBComment"]; if ($this->login_type == 'subscriber') { if ($this->availableGroups[$key]['SubscriberMayEditIt']) { $disabled_box = ""; } else { $disabled_box = "disabled=true"; } } elseif ($this->login_type == 'reseller') { if ($this->availableGroups[$key]['ResellerMayEditIt']) { $disabled_box = ""; } else { $disabled_box = "disabled=true"; } } if ($key=="free-pstn" && !$this->pstn_changes_allowed) { $disabled_box = "disabled=true"; } if ($key=="blocked" && $checked_box[$key]) { $_class="alert alert-error"; $_class1="error"; } else { $_class=""; $_class1=''; } print "
"; if ($key=="blocked") { if ($this->Preferences['blocked_by']) { $selected_blocked_by[$this->Preferences['blocked_by']]='selected'; } else if ($checked_box[$key]) { $selected_blocked_by['reseller']='selected'; } if ($this->login_type == 'admin' || $this->login_type == 'reseller') { if ($this->customer != $this->reseller || $selected_blocked_by['customer']) { printf (" ", $key, $selected_blocked_by['customer'], _("Blocked by Customer"), $this->customer, $selected_blocked_by['reseller'], _("Blocked by Reseller"), $this->reseller ); } else if ($this->reseller) { printf (" ", $key, _("Active"), $selected_blocked_by['reseller'], _("Blocked by Reseller"), $this->reseller ); } else { printf (" ", $key, _("Active"), $selected_blocked_by['reseller'], _("Blocked") ); } } else if ($this->login_type == 'customer' ) { if (in_array($key,$this->groups)) { if ($this->Preferences['blocked_by'] != 'reseller') { printf (" ", $key, _("Active"), $selected_blocked_by['customer'], _("Blocked") ); } else { print _("Blocked by Reseller"); } } else { printf (" ", $key, _("Active"), $selected_blocked_by['customer'], _("Blocked") ); } } else { if (in_array($key,$this->groups)) { print _("Blocked"); } else { print _("Active"); } } } else if ($key=="free-pstn") { if ($this->pstn_changes_allowed) { print " rpid\">"; } else { print ""; } else { print "$elementComment"; } } } else { print " "; } print "
"; } $this->showExtraGroups(); $this->showOwner(); $this->showQuickDial(); $this->showMobileNumber(); $this->showIPAccessList(); $this->showCallLimit(); print "
"); print "s",$this->timeout); print "
"; if (in_array("free-pstn",$this->groups) && !$this->show_barring_tab) { print "
"; if ($this->Preferences['show_barring_tab']){ $check_show_barring_tab="checked"; } else { $check_show_barring_tab=""; } printf ("\n",$check_show_barring_tab,_("Barring")); print "
"; } $this->showVoicemail(); $this->showBillingProfiles(); $chapter=sprintf(_("Notifications Address")); $this->showChapter($chapter); print "
email\">
"; print " "; print "
"; print "
"; print $this->hiddenElements; print " "; } function showDiversionsTab () { if (in_array("trunking",$this->groups)) { return false; } $this->getVoicemail(); $this->getEnumMappings(); $this->getDivertTargets(); $this->getDiversions(); print "
"; $chapter=sprintf(_("Call Forwarding")); $this->showChapter($chapter); $this->showDiversions(); print "
"; print " "; print "
"; print $this->hiddenElements; print "
"; } function showVoicemail() { if ($this->voicemail['Account']) { $checked_voicemail="checked"; } $chapter=sprintf(_("Voice Mailbox")); $this->showChapter($chapter); print "
"; if ($this->voicemail['Account']) { print "
"; if ($this->voicemail['Options']->delete=="True") { $checked_delete_voicemail="checked"; $selected_store_voicemail['email'] ="selected"; $selected_store_voicemail['server'] =""; } else { $selected_store_voicemail['email'] =""; $selected_store_voicemail['server'] ="selected"; } if (!$this->voicemail['DisableOptions']) { print ""; } else { printf (_("Voice messages are sent by email to %s"),$this->email); } print "
"; if (!$this->voicemail['DisableOptions']) { print "
"; printf ("",$this->voicemail['Password']); print "
"; if ($this->voicemail_access_number) { print "
"; printf(_("Dial %s to listen to your messages or change preferences. "),$this->voicemail_access_number); print "
"; } } } } function showOwner() { if ($this->login_type == 'subscriber') { //print "owner\">"; return true; } print "
owner\">"; print "
"; } function showDevicesTab() { $this->getDeviceLocations(); if (count($this->locations)) { $chapter=sprintf(_("SIP Devices")); $this->showChapter($chapter); $j=0; print "
"; foreach (array_keys($this->locations) as $location) { $j++; $contact = $this->locations[$location]['contact']; $publicContact = $this->locations[$location]['publicContact']; $expires = normalizeTime($this->locations[$location]['expires']); $user_agent = $this->locations[$location]['user_agent']; $transport = $this->locations[$location]['transport']; $UAImage = $this->getImageForUserAgent($user_agent); $rr=floor($j/2); $mod=$j-$rr*2; if ($mod ==0) { $_class='odd'; } else { $_class='even'; } print ""; print ""; print ""; } print "
"; printf ("",$this->SipUAImagesPath,$UAImage); print ""; print "$user_agent"; if ($transport == 'tls') print " "; print "
"; print _("Location"); print ""; print " "; if (strlen($transport)) print "$transport:"; print "$contact "; if ($publicContact != $contact) { print " ($publicContact) "; } if ($publicContact) { $_els=explode(":",$publicContact); if ($_loc=geoip_record_by_name($_els[0])) { $this->geo_location=$_loc['country_name'].'/'.utf8_encode($_loc['city']); } else if ($_loc=geoip_country_name_by_name($_els[0])) { $this->geo_location=$_loc; } else { $this->geo_location=''; } printf ("%s",$this->geo_location); } print "
$expires
"; } } function getBarringPrefixes() { dprint("getBarringPrefixes()"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getBarringPrefixes($this->sipId); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } $this->barring_prefixes=$result; return true; } function setBarringPrefixes() { dprint("setBarringPrefixes"); $prefixes=array(); $barring_prefixes=$_REQUEST['barring_prefixes']; foreach ($barring_prefixes as $_prefix) { if (preg_match("/^\+[1-9][0-9]*$/",$_prefix)) { $prefixes[]=$_prefix; } } dprint("setBarringPrefixes"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->setBarringPrefixes($this->sipId,$prefixes); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } } function showBarringTab() { $chapter=sprintf(_("Barred Destinations")); $this->showChapter($chapter); print "

"; print "
"; print _("You can deny outbound calls to unwanted PSTN prefixes. "); print "
"; print "
"; print "
"; print ""; print _("Example"); print ": +31900"; print "
"; if ($this->getBarringPrefixes()) { foreach ($this->barring_prefixes as $_prefix) { $found++; $rr=floor($found/2); $mod=$found-$rr*2; if ($mod == 0) { $_class='odd'; } else { $_class='even'; } print "
"; print ""; print "
"; print "
"; } } print " "; print "
"; print "
"; print $this->hiddenElements; print " "; } function saveSettings() { $this->getVoicemail(); /* $this->getEnumMappings(); $this->getDivertTargets(); $this->getDiversions(); */ $this->changedFields=array(); $this->sendCEmail=0; foreach ($this->form_elements as $el) { ${$el} = $_REQUEST[$el]; } $newACLarray = array(); $result = $this->result; if (!is_array($result->properties)) $result->properties=array(); if (!is_array($result->groups)) $result->groups=array(); if ($mailto && $this->email != $mailto) { $result->email=$mailto; $this->email=$mailto; $this->somethingChanged=1; $this->voicemailOptionsHaveChanged=1; $this->sendCEmail=1; array_push($this->changedFields,"Email Address"); } if ($this->login_type != "subscriber") { if ($first_name && $this->firstName != $first_name) { $result->firstName = $first_name; $this->firstName = $first_name; $this->somethingChanged=1; $this->voicemailOptionsHaveChanged=1; } if ($last_name && $this->lastName != $last_name) { $result->lastName = $last_name; $this->lastName = $last_name; $this->somethingChanged=1; } } $this->properties=$result->properties; $this->availableGroups['voicemail']=array("Group"=>"voicemail", "WEBName" =>sprintf (_("Voice Mailbox")), "SubscriberMayEditIt"=>"1", "SubscriberMaySeeIt"=>0 ); if (!$this->voicemail['Account'] && $voicemail) { if ($this->addVoicemail()) { $this->setVoicemailDiversions(); $this->createdVoicemailnow=1; } } else if ($this->voicemail['Account'] && !$voicemail) { if ($this->deleteVoicemail()) { $this->voicemail['Account']=""; $this->removeVoicemailDiversions(); } } if ($this->pstn_changes_allowed) { if (strcmp($quota,$this->quota) != 0) { if (!$quota) $quota=0; $result->quota=intval($quota); dprint ("change the quota"); $this->somethingChanged=1; } if ($quota_deblock) { $result->groups = array_unique(array_diff($this->groups,array('quota'))); $this->somethingChanged=1; $this->SipPort->addHeader($this->SoapAuth); $this->SipPort->removeFromGroup(array("username" => $this->username,"domain"=> $this->domain), "quota"); } $rpid=trim($rpid); if (strcmp($rpid,$this->rpid) != 0) { dprint ("change the rpid"); $result->rpid=$rpid; $this->somethingChanged=1; } if ($this->CallLimitChangePolicy()) { if ($this->soapEngines[$this->sip_engine]['call_limit']) { if (isset($callLimit) && $this->callLimit != $callLimit) { $result->callLimit=intval($callLimit); $this->somethingChanged=1; } } } } $owner=intval($owner); if ($owner != $this->owner && $this->login_type != 'subscriber') { dprint ("change the owner"); $result->owner=$owner; $this->somethingChanged=1; } else { $result->owner=$this->owner; } if ($this->prepaid_changes_allowed) { if(!$result->prepaid && $_REQUEST['prepaid']){ if ($result->quota) { $this->somethingChanged=1; } $this->somethingChanged=1; } else if ($result->prepaid && !$_REQUEST['prepaid']) { $this->somethingChanged=1; } $result->prepaid=intval($_REQUEST['prepaid']); } reset($this->availableGroups); foreach (array_keys($this->availableGroups) as $key) { // $val is set to 1 if web checkbox is ticked $val = $_REQUEST[$key]; if ($this->login_type != 'subscriber' || $this->availableGroups[$key]['SubscriberMayEditIt']) { if ($key == 'free-pstn') { if (in_array($key,$this->groups) && !$val) { if ($this->quota) { // we save quota for later use when pstn access is re-granted $this->somethingChanged=1; $this->setPreference('last_sip_quota',"$this->quota"); } $this->somethingChanged=1; } else if (!in_array($key,$this->groups) && $val) { if (!$this->prepaid_changes_allowed) { $this->somethingChanged=1; $result->prepaid=1; } } if (!in_array($key,$this->groups) && $val) { $this->setPreference('last_sip_quota',strval($this->quota)); $last_sip_quota=$this->Preferences['last_sip_quota']; if ($last_sip_quota) { $result->quota=intval($last_sip_quota); $this->somethingChanged=1; } } if ($this->pstn_changes_allowed) { if ($val) $newACLarray[]=trim($key); } else { if (in_array($key,$this->groups)) { $newACLarray[]=trim($key); } } } else if ($key == 'trunking') { if ($this->login_type == 'admin' || $this->login_type == 'reseller') { if (!$val && in_array($key,$this->groups)) { # TODO remove diversions } } if ($val) $newACLarray[]=trim($key); } else if ($key == 'blocked') { if ($this->login_type == 'admin' || $this->login_type == 'reseller') { if ($val && $val != $this->Preferences['blocked_by']) { $this->setPreference('blocked_by',$val); $this->somethingChanged=1; } else if (!$val && in_array($key,$this->groups)) { $this->somethingChanged=1; $this->setPreference('blocked_by',''); } if ($val) $newACLarray[]=trim($key); } else if ($this->login_type == 'customer' ) { if ($this->Preferences['blocked_by'] != 'reseller') { if ($val && ($val != $this->Preferences['blocked_by'] || !in_array($key,$this->groups) )) { $this->setPreference('blocked_by',$val); $this->somethingChanged=1; $newACLarray[]=trim($key); } else if (!$val && in_array($key,$this->groups)) { $this->somethingChanged=1; $this->setPreference('blocked_by',''); } if ($val) $newACLarray[]=trim($key); } else { // copy old setting if exists if (in_array($key,$this->groups)) { $newACLarray[]=trim($key); } } } } else if ($key == 'sms') { if ($this->sms_changes_allowed) { if (!$val && in_array($key,$this->groups)) { $this->somethingChanged=1; } else if ($val && !in_array($key,$this->groups)) { $this->somethingChanged=1; } if ($val) $newACLarray[]=trim($key); } else { // copy old setting if exists if (in_array($key,$this->groups)) { $newACLarray[]=trim($key); } } } else { if ($val) $newACLarray[]=trim($key); } } else { // copy old setting if exists if (in_array($key,$this->groups)) { $newACLarray[]=trim($key); } } } $foundGroupInAvailableGroups=array(); $extra_groups=explode(' ',$_REQUEST['extra_groups']); foreach ($extra_groups as $_grp) { if (!in_array($_grp,array_keys($this->availableGroups))) { $newACLarray[]=$_grp; } } $grantACLarray = array_unique(array_diff($newACLarray,$this->groups)); $revokeACLarray = array_unique(array_diff($this->groups,$newACLarray)); /* dprint_r($this->groups); dprint_r($newACLarray); dprint_r($grantACLarray); dprint_r($revokeACLarray); */ if (count($revokeACLarray) || count($grantACLarray)) { $result->groups=$newACLarray; $this->somethingChanged=1; } if ($language && $language != $this->Preferences['language'] ) { if ($this->login_type == 'subscriber') {; //print("Set lang $language"); $this->changeLanguage($language); } $this->setPreference("language",$language); $this->somethingChanged=1; } if ($show_barring_tab != $this->Preferences['show_barring_tab'] ) { $this->setPreference("show_barring_tab",$show_barring_tab); $this->somethingChanged=1; } if ($this->Preferences['account_delete_request'] ) { $this->setPreference("account_delete_request",date('m/d/Y h:i:s a', time())); $this->somethingChanged=1; } if ($this->login_type == 'subscriber' && in_array("deny-password-change",$this->groups)) { } else if ($sip_password) { if ($this->store_clear_text_passwords) { $result->password=$sip_password; } else { $md1=strtolower($this->username).':'.strtolower($this->domain).':'.$sip_password; $md2=strtolower($this->username).'@'.strtolower($this->domain).':'.strtolower($this->domain).':'.$sip_password; $result->password=md5($md1).':'.md5($md2); } $this->sendCEmail=1; array_push($this->changedFields,"Password"); $this->somethingChanged=1; } if ($web_password) { if ($this->store_clear_text_passwords) { $web_password_new=$web_password; } else { $md1=strtolower($this->username).':'.strtolower($this->domain).':'.$web_password; $md2=strtolower($this->username).'@'.strtolower($this->domain).':'.strtolower($this->domain).':'.$web_password; $web_password_new=md5($md1).':'.md5($md2); } $this->setPreference('web_password',$web_password_new); $this->sendCEmail=1; array_push($this->changedFields,"Web password"); $this->somethingChanged=1; } if ($web_password_reset) { $this->setPreference('web_password','remove'); $this->somethingChanged=1; } if ($this->Preferences['yubikey'] != $yubikey && !$this->isEmbedded()) { $this->setPreference('yubikey',$yubikey); $this->somethingChanged=1; } if (is_array($result->acl) and count($result->acl)) { foreach (array_keys($result->acl) as $key) { if (isset($result->acl[$key]->tag) && $result->acl[$key]->tag == '') { unset($result->acl[$key]->tag); } } } if ($this->IPAccessListChangePolicy()) { if (isset($ip_access_list) and $this->ip_access_list != $ip_access_list) { $ip_access_list=preg_replace("/\s+/","\n", trim($ip_access_list)); $list=explode("\n", trim($ip_access_list)); $ip_access_list=array(); foreach ($list as $el) { list($ip,$mask) = explode("/",$el); if ($mask <0 or $mask > 32) { continue; } if (!preg_match("/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/",$ip)) { continue; } $ip_access_list[]=array('ip'=>$ip, 'mask'=>intval($mask)); } $result->acl=$ip_access_list; $this->somethingChanged=1; } } if (!$result->password) unset($result->password); if ($timezone && $timezone != $this->timezone) { $result->timezone=$timezone; $this->somethingChanged=1; } if ($region != $this->region) { $result->region=$region; $this->somethingChanged=1; } if (strcmp($quickdial,$this->quickdial) != 0) { $result->quickdialPrefix=$quickdial; $this->somethingChanged=1; } $mobile_number = preg_replace("/[^\+0-9]/","",$mobile_number); if ($mobile_number && !preg_match("/^\+/",$mobile_number)) { $mobile_number='+'.$mobile_number; } if ($this->Preferences['mobile_number'] != $mobile_number) { $this->setPreference('mobile_number',$mobile_number); $this->somethingChanged=1; } if (!$this->createdVoicemailnow) { // moved to its own tab //$this->setDiversions(); } if ($this->timeoutWasNotSet || $timeout != $this->timeout) { $this->somethingChanged=1; $result->timeout=intval($timeout); } if ($result->owner == '') { $this->somethingChanged=1; $result->owner=0; } if ($result->callLimit == '') { $this->somethingChanged=1; $result->callLimit=0; } if ($result->quota == '') { $this->somethingChanged=1; $result->quota=0; } if ($result->timeout == '') { $this->somethingChanged=1; $result->timeout=35; } if ($result->timeout > 900) { $this->somethingChanged=1; $result->timeout=900; } if ($this->somethingChanged) { $result->properties=$this->properties; if (!$result->quota) $result->quota=0; //dprint_r($result); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->updateAccount($result); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { dprint("Call updateAccount"); if ($this->sendCEmail && $this->notify_on_sip_account_changes) { $this->sendChangedEmail(False,$this->changedFields); } } } if ($this->voicemail['Account'] && !$this->createdVoicemailnow) { $delete_voicemail = $_REQUEST['delete_voicemail']; //$log=sprintf("delete_voicemail_orig=%s",$this->voicemail['Options']->delete); //dprint($log); if (($delete_voicemail && !$this->voicemail['Options']->delete) || (!$delete_voicemail && $this->voicemail['Options']->delete)) { $this->voicemail['Options']=array("delete"=>intval($delete_voicemail)); $this->voicemailOptionsHaveChanged=1; } $voicemail_password=preg_replace("/[^0-9]/","",$voicemail_password); if ($this->voicemail['Password'] != $voicemail_password) { $this->voicemailOptionsHaveChanged=1; $this->voicemail['Password']=$voicemail_password; } if ($this->voicemailOptionsHaveChanged) { $this->updateVoicemail(); } } $this->updateBillingProfiles(); } function setDiversions() { dprint ("setDiversions()"); $this->getVoicemail(); $this->getEnumMappings(); $this->getDivertTargets(); $this->getDiversions(); foreach (array_keys($this->diversionType) as $condition) { $select_name = $condition."_select"; $selectedIdx = $_REQUEST[$select_name]; $textboxURI = $_REQUEST[$condition]; if ($textboxURI && $textboxURI != "" && !preg_match("/@/",$textboxURI)) { $textboxURI=$textboxURI."@".$this->domain; } if (preg_match("/^([\+|0].*)@/",$textboxURI,$m)) { $textboxURI=$m[1]."@".$this->domain; } $uri_description = $this->divertTargets[$selectedIdx]['description']; if ($uri_description == 'Other' || $textboxURI == "") { $selectedURI = $textboxURI; } else { $selectedURI = $this->divertTargets[$selectedIdx]['value']; } $uri = $selectedURI; if (!$this->voicemail['Account'] && $uri_description == 'Voicemail') { dprint("No voicemail account found"); $uri_description='Disabled'; } if ($this->diversions[$condition]) { if ($uri_description=='Disabled' && $this->CallPrefUriType[$condition]!='Disabled') { $diversions[$condition]=""; } else if ($uri_description != 'Disabled' && $selectedURI) { if (checkURI($selectedURI)) { if ($this->CallPrefUriType[$condition]=='Disabled') { $diversions[$condition]=""; } else { if ($this->diversions[$condition] != $uri) { $diversions[$condition]=$uri; } else { $diversions[$condition]=$this->diversions[$condition]; } } } else { $diversions[$condition]=$this->diversions[$condition]; dprint("Failed to check address $selectedURI"); } } } else if ($uri_description!='Disabled' && $selectedURI) { if (checkURI($selectedURI)) { $diversions[$condition]=$uri; } else { dprint("Failed to check address $condition=\"$selectedURI\""); $diversions[$condition]=$this->diversions[$condition]; } } if (!$uri_description) $uri_description="Other"; if ($uri_description == 'Other') { $last_other=$uri; } else { $last_other = $this->CallPrefLastOther[$condition]; } $_prefLast = $condition."_lastOther"; if ($uri_description=='Other' && $this->Preferences[$_prefLast] != $last_other ) { $this->setPreference($_prefLast,$last_other); } } foreach(array_keys($this->diversions) as $key) { if ($this->diversions[$key] != $diversions[$key]) { //$log=sprintf("Diversion %s changed from %s to %s",$key,htmlentities($this->diversions[$key]),htmlentities($diversions[$key])); dprint($log); $divert_changed=1; } if ($diversions[$key]) { if ($diversions[$key] == "") { if ($this->absolute_voicemail_uri) { $diversionsSOAP[$key] = 'sip:'.$this->voicemail['Account']; } else { $diversionsSOAP[$key] = $diversions[$key]; } } else { $diversionsSOAP[$key]='sip:'.$diversions[$key]; } } else { if ($diversions[$key]) $diversionsSOAP[$key]=$diversions[$key]; } } if (!is_array($diversionsSOAP) || count($diversionsSOAP) == 0) { $diversionsSOAP=array("nocondition"=>"empty"); } if ($divert_changed) { $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->setCallDiversions($this->sipId,$diversionsSOAP); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error2 (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { $this->diversions=$diversions; } } } function setDiversion($condition,$uri) { dprint ("setDiversion($condition,$uri)"); $condition=trim($condition); $uri=trim($uri); $this->getVoicemail(); $this->getDivertTargets(); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getCallDiversions($this->sipId); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } $_uri_saved=$uri; if ($_uri_saved == "voicemail") { $uri=""; foreach ($this->divertTargets as $target) { if ($target['description'] == 'Voicemail') { $uri=$target['value']; break; } } } if ($_uri_saved == "mobile") { $uri=""; foreach ($this->divertTargets as $target) { dprint_r($target); if ($target['description'] == 'Mobile') { $uri=$target['value']; break; } } } if ($_uri_saved == "other" && $this->CallPrefLastOther[$condition]) { $uri=$this->CallPrefLastOther[$condition]; } if (strlen($uri)) { if ($uri != "") { if (!preg_match("/^(sip:|sips:)/",$uri)) $uri="sip:".$uri; } } else { $uri=NULL; } reset($this->diversionType); foreach(array_keys($this->diversionType) as $_condition) { $uri=$result->$_condition; if ($this->absolute_voicemail_uri && $uri == "") { $uri = $this->voicemail['Account']; } if (preg_match("/^(sip:|sips:)(.*)$/i",$uri,$m)) { $uri=$m[2]; } //if (!$uri) $uri=NULL; $this->diversions[$condition]=$uri; } dprint_r($this->diversions); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->setCallDiversions($this->sipId,$result); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } } function setVoicemailDiversions() { dprint ("setVoicemailDiversions()"); if ($this->getVoicemail()) { if (!$this->absolute_voicemail_uri) { $diversions['FBUS']=""; $diversions['FNOA']=""; $diversions['FNOL']=""; } else { $diversions['FBUS']="sip:".$this->voicemail['Account']; $diversions['FNOA']="sip:".$this->voicemail['Account']; $diversions['FNOL']="sip:".$this->voicemail['Account']; } $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->setCallDiversions($this->sipId,$diversions); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } } } function removeVoicemailDiversions() { dprint ("removeVoicemailDiversions()"); $this->getDiversions(); $diversions=array(); foreach (array_keys($this->diversionType) as $key) { if ($this->diversions[$key]=="" || preg_match("/voicemail_server/",$this->diversions[$key])) { $diversions_have_changed=true; } else { if ($this->diversions[$key]) { $diversions[$key]=$this->diversions[$key]; } } } if (!count($diversions)) { $diversions['nocondition']='empty'; } if ($diversions_have_changed) { $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->setCallDiversions($this->sipId,$diversions); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } } else { return true; } } function updateVoicemail() { dprint("updateVoicemail()"); $account=array("sipId" => $this->sipId, "email" => $this->email, "name" => $this->firstName.' '.$this->lastName, "password" => $this->voicemail['Password'], "options" => $this->voicemail['Options'] ); dprint_r($account); $this->VoicemailPort->addHeader($this->SoapAuthVoicemail); $result = $this->VoicemailPort->updateAccount($account); if ((new PEAR)->isError($result)) { $error_msg=$result->getMessage(); $error_fault=$result->getFault(); $error_code=$result->getCode(); print "$error_msg\n"; printf ("

Error (VoicemailPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } return true; } function addVoicemail() { dprint("addVoicemail()"); $password=$this->RandomPassword(); $_account = array("sipId" => $this->sipId, "name" => $this->fullName, "password" => $password, "email" => $this->email, "options" => array("delete"=>1) ); $this->VoicemailPort->addHeader($this->SoapAuthVoicemail); $result = $this->VoicemailPort->addAccount($_account); if ((new PEAR)->isError($result)) { $error_msg=$result->getMessage(); $error_fault=$result->getFault(); $error_code=$result->getCode(); print "$error_msg\n"; printf ("

Error (VoicemailPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } return true; } function deleteVoicemail() { dprint("deleteVoicemail()"); $this->VoicemailPort->addHeader($this->SoapAuthVoicemail); $result = $this->VoicemailPort->deleteAccount($this->sipId); if ((new PEAR)->isError($result)) { $error_msg=$result->getMessage(); $error_fault=$result->getFault(); $error_code=$result->getCode(); print "$error_msg\n"; printf ("

Error (VoicemailPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } return true; } function setPreference($name,$value) { dprint("setPreference($name,$value)"); if (!$name) return; if (!is_array($this->properties)) { $this->properties=array(); } foreach (array_keys($this->properties) as $_key) { $_prop=$this->properties[$_key]; if ($_prop->name == $name) { if (strlen($value)) { if ($value != 'remove') { $newProperties[]=array('name'=> $name, 'value' => $value); } } $found=1; } else { $newProperties[]=$_prop; } } if (!$found) { $newProperties[]=array('name' => $name, 'value' => $value); } if ($this->properties!=$newProperties) $this->somethingChanged=1; if (!$newProperties) $newProperties = array(); $this->properties=$newProperties; //dprint_r($this->properties); } function showCreditTab() { if ($this->login_type == 'subscriber' && in_array("blocked",$this->groups)) { return false; } $task = $_REQUEST['task']; $issuer = $_REQUEST['issuer']; $prepaidCard = $_REQUEST['prepaidCard']; $prepaidId = $_REQUEST['prepaidId']; $_done = false; if ($issuer) { print " "; if ($issuer=='subscriber'){ if ($prepaidCard && $prepaidId) { if ($result = $this->addBalanceSubscriber($prepaidCard,$prepaidId)) { print "

"; printf (_("Old balance was %s, new balance is %s. "),$result->old_balance, $result->new_balance); print ""; $_done=true; } } } else if ($issuer=='reseller' || $issuer=='admin') { if ($_REQUEST['task'] == 'change_balance') { $description = $_REQUEST['description']; $value = $_REQUEST['value']; if (strlen($value) && $result = $this->addBalanceReseller($value,$description)) { print "

"; printf (_("Old balance was %s, new balance is %s. "),$result->old_balance, $result->new_balance); print ""; $_done=true; } } else if ($_REQUEST['task'] == 'refund') { $transaction = json_decode(base64_decode($_REQUEST['transaction'])); printf ("Refunding transaction id %s in value of %s", $transaction->id, $transaction->value); require('cc_processor.php'); $ccp = new CreditCardProcessor(); $refund_results = $ccp->refundPayment($transaction->id); if(count($refund_results['error']) > 0 ){ printf ("

Error %d: %s (%s)",$refund_results['error']['error_code'], $refund_results['error']['desc'], $refund_results['error']['short_message']); } else { printf ("

Transaction %s refunded with %s: %s",$transaction->id, $refund_results['success']['desc']->RefundTransactionID,$refund_results['success']['desc']->GrossRefundAmount->_value); $description=sprintf("Refund %s with %s",$transaction->id, $refund_results['success']['desc']->RefundTransactionID); if ($result = $this->addBalanceReseller(-$transaction->value,$description)) { print "

"; printf (_("Old balance was %s, new balance is %s. "),$result->old_balance, $result->new_balance); print ""; $_done=true; } } } } if ($_done && $_REQUEST['notify']) { $subject=sprintf ("SIP Account %s balance update",$this->account); $body="Your SIP Account balance has been updated. ". "For more details go to $this->sip_settings_page?tab=credit"; if (mail($this->email, $subject, $body, "From: $this->support_email")) { printf (_("Subscriber has been notified at %s."), $this->email); } } print " "; } $this->getPrepaidStatus(); if ($this->prepaidAccount) { $chapter=sprintf(_("Current Balance")); $this->showChapter($chapter); print "

"; print _("Your current balance is"); print ": "; printf ("%.2f %s ",$this->prepaidAccount->balance,$this->currency); print "
"; $this->showChangeBalanceReseller(); $this->showChangeBalanceSubscriber(); $this->showBalanceHistory(); } } function showChangeBalanceReseller () { if (!$this->prepaid_changes_allowed) return false; $chapter=sprintf(_("Add Balance")); $this->showChapter($chapter); print "
url method=post>
"; print " "; print ""; print " "; print "
"; $transactions = $this->getPaymentIds(); if (count($transactions)) { $chapter=sprintf(_("Refund Transaction")); $this->showChapter($chapter); print "
url method=post> "; print _("Transaction Id"); print " "; print " Notify
"; } } function showChangeBalanceSubscriber () { $this->showPrepaidVoucherForm(); } function showPrepaidVoucherForm () { if ($this->isEmbedded()) return true; $chapter=sprintf(_("Prepaid Card")); $this->showChapter($chapter); print "
"; printf (_("To add Credit to your account using a Prepaid Card enter it below. ")); print "
"; print "
url method=post>
"; print " "; print ""; if ($this->login_type != 'subscriber') { print " "; } print "
"; } function getPrepaidStatus() { dprint("getPrepaidStatus()"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getPrepaidStatus(array($this->sipId)); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); unset($this->prepaidAccount); return false; } else { $this->prepaidAccount=$result[0]; return true; } } function addBalanceSubscriber($prepaidCard,$prepaidId) { dprint("addBalanceSubscriberLocal($prepaidCard,$prepaidId)"); $card = array('id' => intval($prepaidId), 'number' => $prepaidCard ); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->addBalanceFromVoucher($this->sipId,$card); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { return $result; } } function addBalanceReseller($value=0,$description='') { $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->addBalance($this->sipId,floatval($value),$description); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { return $result; } } function getBalanceHistory() { dprint("getBalanceHistory()"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getCreditHistory($this->sipId,200); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); if ($error_fault->detail->exception->errorcode != "2000") { printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); } } $this->balance_history=$result->entries; } function getPaymentIds() { $transactions = array(); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getCreditHistory($this->sipId,200); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); if ($error_fault->detail->exception->errorcode != "2000") { printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); } } $refunded_transactions=array(); $credit_transactions=array(); foreach ($result->entries as $entry) { if (preg_match("/^CC transaction (.*)$/",$entry->description,$m)) { $credit_transactions[$m[1]]=$entry->value; } if (preg_match("/^Refund (.*) with (.*)$/",$entry->description,$m)) { $refunded_transactions[]=$m[1]; } } foreach (array_keys($credit_transactions) as $tran) { if (!in_array($tran, $refunded_transactions)) { $transactions[$tran] = $credit_transactions[$tran]; } } return $transactions; } function getTodayBalanceSummary() { $total_debit = 0; $total_credit = 0; foreach ($this->balance_history as $_line) { $value=$_line->value; if (substr($_line->date,0,10) != date("Y-m-d")) { break; } if ($value <0) { $total_debit+=$value; } if ($value >0) { $total_credit+=$value; } } $total = array('debit' => $total_debit, 'credit' => $total_credit ); return $total; } function showBalanceHistory() { $this->getBalanceHistory(); if (!count($this->balance_history)) { return; } $chapter=sprintf(_("Balance History")); $this->showChapter($chapter); print "

"; $today_summary = $this->getTodayBalanceSummary(); if ($today_summary['credit'] >= $max_credit_per_day) { print "

"; printf (_("Today's transactions: %.2f credit, %.2f debit"), $today_summary['credit'],$today_summary['debit']); } print "

"; print ""; print ""; print ""; print ""; print ""; print ""; print ""; print ""; print ""; print ""; foreach ($this->balance_history as $_line) { if (strstr($_line->description,'Session')) { if (!$_line->value) continue; $value=$_line->value; if ($this->cdrtool_address && !$this->isEmbedded()) { $description=sprintf("$_line->description",$this->cdrtool_address,urlencode($_line->session)); } else { $description=$_line->description; } } else { $description=$_line->description; $value=$_line->value; } if ($value <0) { $total_debit+=$value; } if ($value >0) { $total_credit+=$value; } $found++; $rr=floor($found/2); $mod=$found-$rr*2; if ($mod ==0) { $_class='odd'; } else { $_class='even'; } print " "; printf (" ",$found, $_line->date, $_line->action, $description, number_format($value,4), number_format($_line->balance,4) ); } print " "; if (strlen($total_credit)) { printf (" ", _("Total Credit"), number_format($total_credit,4) ); } if (strlen($total_debit)) { printf (" ", _("Total Debit"), number_format($total_debit,4) ); } print "
"; print ""; print _("Date and Time"); print ""; print _("Action"); print ""; print _("Description"); print ""; print _("Value"); print ""; print _("Balance"); print "
%d %s %s %s %s %s
%s %s
%s %s
"; if ($found) { if (!$this->isEmbedded()) { print "

url&tab=credit&action=get_balance_history&csv=1 target=_new data-original-title='"; print _("Export"); print "' data-content='"; print _("Export balance history in CSV format"); print "' rel='popover' onclick=\"window.open('$this->url&tab=credit&action=get_balance_history&csv=1]')\">"; print _("Export"); print "

"; } else { print "

url&tab=credit&action=get_balance_history&csv=1 data-original-title='"; print _("Export"); print "' data-content='"; print _("Export balance history in CSV format"); print "' onclick=\"location.href='$this->url&tab=credit&action=get_balance_history&csv=1';\">"; print _("Export"); print "

"; } } print ""; } function exportBalanceHistory() { Header("Content-type: text/csv"); $h=sprintf("Content-Disposition: inline; filename=%s-prepaid-history.csv",$this->account); Header($h); print _("Id"); print ","; print _("Account"); print ","; print _("Date"); print ","; print _("Action"); print ","; print _("Description"); print ","; print _("Value"); print ","; print _("Final Balance"); print ("\n"); foreach ($this->balance_history as $_line) { if (strstr($_line->description,'Session') && !$_line->value) continue; $found++; printf ("%s,%s,%s,%s,%s,%s,%s\n", $found, $this->account, $_line->date, $_line->action, $_line->description, $_line->value, $_line->balance); } } function showDiversions($conditions=array()) { // for busy not online or unconditional foreach (array_keys($this->diversionType) as $condition) { $_prefName = $condition."_lastOther"; $this->CallPrefLastOther[$condition]= $this->Preferences[$_prefName]; } if (!count($conditions)) { $conditions=$this->diversionType; } foreach (array_keys($conditions) as $condition) { $found++; $rr=floor($found/2); $mod=$found-$rr*2; $pref_name = $conditions[$condition]; $pref_value = $this->diversions[$condition]; $select_name=$condition."_select"; $set_uri_java="set_uri_" . $condition; $update_text_java="update_text_" . $condition; if ($mod ==0) { $_class='odd'; } else { $_class='even'; } print "
"; $phoneValues = array(); foreach ($this->divertTargets as $phones) { $phoneValues[] = $phones['value']; } $lastOther = $this->CallPrefLastOther[$condition]; $otherIdx = count($this->divertTargets) - 1; $phoneValues[$otherIdx] = $lastOther; $targets = sprintf("'%s'", join("', '", $phoneValues)); print " "; print ""; if ($this->CallPrefUriType[$condition]=='Other') $style = "visible"; else $style = "hidden"; $pref_value=$this->diversions[$condition]; print " "; if ($condition=="FUNV" && $this->FUNC_access_number) { print "
"; printf (_("Dial %s2*X where X = Number of Minutes, 0 to Reset"), $this->access_numbers['FUNC']); print "
"; } print "
"; } } function showHeader() { /*print "
";*/ print "
"; if ($this->logoFile) { print "logoFile border=0>"; } print "
"; /* print "
"; */ } function chapterTableStart() { } function chapterTableStop() { } function getEnumMappings () { dprint("getEnumMappings()"); $this->enums=array(); $filter=array( 'type' => 'sip', 'mapto' => $this->account, 'owner' => intval($this->owner) ); // Range $range=array('start' => 0, 'count' => 10 ); // Order $orderBy = array('attribute' => 'changeDate', 'direction' => 'ASC' ); // Compose query $Query=array('filter' => $filter, 'orderBy' => $orderBy, 'range' => $range ); // Insert credetials $this->EnumPort->addHeader($this->SoapAuthEnum); $result = $this->EnumPort->getNumbers($Query); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (EnumPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } foreach($result->numbers as $_number) { $enum='+'.$_number->id->number; $this->voicemailUsernameOptions[]=$enum; if (!in_array($enum,$this->enums)) $this->enums[]=$enum; } } function enum2tel($enum_text) { // transform enum style domain name in forward telephone number $enum_text=trim($enum_text); if (preg_match("/^\+\d+$/",$enum_text)) { return $enum_text; } $z=0; $tel_text=""; while ($z < strlen($enum_text)) { $char = substr($enum_text,$z,1); if (preg_match("/[a-zA-Z]/",$char)) { break; } else if (preg_match("/[0-9]/",$char)) { $tel_text=$char.$tel_text; $z++; } else { $z++; } } if ($tel_text) { $tel_text="+".$tel_text; return ($tel_text); } else { return $enum_text; } } function showTimezones($name,$value) { if (!$fp = fopen("timezones", "r")) { print _("Failed to open timezone file."); return false; } printf (""; } function showQuickDial() { if (!preg_match("/^\d+$/",$this->username)) return 1; print "

quickdial\">"; if ($this->quickdial && preg_match("/^$this->quickdial/",$this->username)) { $dial_suffix=strlen($this->username) - strlen($this->quickdial); } printf (_("Prefix to auto-complete short numbers"),$dial_suffix); print "
"; } function showMobileNumber() { if (in_array("free-pstn",$this->groups)) { print "
%s
",$this->Preferences['mobile_number'],_("International format starting with +")); } } function CallLimitChangePolicy() { if ($this->login_type == 'subscriber' and $this->call_limit_may_by_changed_by == 'reseller') { return false; } if ($this->login_type == 'subscriber' and $this->call_limit_may_by_changed_by == 'customer') { return false; } if ($this->login_type == 'subscriber' and $this->call_limit_may_by_changed_by == 'admin') { return false; } if ($this->login_type == 'customer' and $this->call_limit_may_by_changed_by == 'reseller') { return false; } if ($this->login_type == 'customer' and $this->call_limit_may_by_changed_by == 'admin') { return false; } if ($this->login_type == 'reseller' and $this->call_limit_may_by_changed_by == 'admin') { return false; } return true; } function IPAccessListChangePolicy() { if ($this->login_type == 'subscriber' and $this->ip_access_list_may_by_changed_by == 'reseller') { return false; } if ($this->login_type == 'subscriber' and $this->ip_access_list_may_by_changed_by == 'customer') { return false; } if ($this->login_type == 'subscriber' and $this->ip_access_list_may_by_changed_by == 'admin') { return false; } if ($this->login_type == 'customer' and $this->ip_access_list_may_by_changed_by == 'reseller') { return false; } if ($this->login_type == 'customer' and $this->ip_access_list_may_by_changed_by == 'admin') { return false; } if ($this->login_type == 'reseller' and $this->ip_access_list_may_by_changed_by == 'admin') { return false; } return true; } function showIPAccessList() { if (!$this->soapEngines[$this->sip_engine]['ip_access_list']) { return; } if (!$this->IPAccessListChangePolicy()) { print "
%s
",$this->ip_access_list); } else { print "
",$this->ip_access_list); } } function showCallLimit() { if (!$this->pstn_access) { return; } if (!in_array("free-pstn",$this->groups)) { return; } if (!$this->soapEngines[$this->sip_engine]['call_limit']) { return; } $limit_text = sprintf(_("Default is %s"), $this->platform_call_limit); if (strlen($this->callLimit)) { $limit_text_ro=$this->callLimit; } else { $limit_text_ro=$this->platform_call_limit; } if (!$this->CallLimitChangePolicy()) { print "
%s
",$limit_text_ro); } else { print "
%s
",$this->callLimit, $limit_text); } } function showCallsTab() { $this->getHistory(); if ($this->calls) { $chapter=sprintf(_("Call Statistics")); $this->showChapter($chapter); $calltime=normalizeTime($this->duration); print " "; if ($this->cdrtool_address) { print "cdrtool_address target=cdrtool>"; print _("Summary"); print ""; } else { print _("Usage Data"); } print " "; printf (_("%s calls / %s / %s / %.2f %s"), $this->calls, $calltime,$this->trafficPrint,$this->price,$this->currency); print " "; print " "; print _("First / Last Call"); print " $this->firstCall / $this->lastCall "; } if ($this->enable_thor) { $cdr_source = 'sipthor'; } else { $cdr_source = 'sip_trace'; } if (count($this->calls_received)) { $chapter=sprintf(_("Incoming")); $this->showChapter($chapter); $j=0; print ""; foreach (array_keys($this->calls_received) as $call) { $j++; $uri = $this->calls_received[$call]['remoteParty']; $media=""; foreach ($this->calls_received[$call]['media'] as $m) { $media.="$m,"; } $media=quoted_printable_decode($media); $media=rtrim($media,","); $duration = normalizeTime($this->calls_received[$call]['duration']); $dialURI = $this->PhoneDialURL($uri) ; $htmlDate = $this->colorizeDate($this->calls_received[$call]['startTime']); $htmlURI = $this->htmlURI($uri); $urlURI = urlencode($this->normalizeURI($uri)); $sessionId = urlencode($this->calls_received[$call]['sessionId']); $fromTag = urlencode($this->calls_received[$call]['fromTag']); $toTag = urlencode($this->calls_received[$call]['toTag']); $proxyIP = urlencode($this->calls_received[$call]['proxyIP']); $trace_link = "Server Logs"; if (!$this->calls_received[$call]['duration']) { $htmlURI = "$htmlURI"; } $rr=floor($j/2); $mod=$j-$rr*2; if ($mod ==0) { $_class='odd'; } else { $_class='even'; } print " "; print ""; print ""; print " "; } print "
$htmlDate $dialURI $duration $htmlURI ($media)$trace_linkurl&tab=contacts&task=add&uri=$urlURI&search_text=$urlURI>$this->phonebook_img
"; } if (count($this->calls_placed)) { $chapter=sprintf(_("Outgoing")); $this->showChapter($chapter); $j=0; print ""; foreach (array_keys($this->calls_placed) as $call) { $j++; if ($this->calls_placed[$call]['to'] == "sip:".$this->voicemail['Account'] ) { continue; } $uri = $this->calls_placed[$call]['remoteParty']; $media = ""; foreach ($this->calls_placed[$call]['media'] as $m) { $media.="$m,"; } $media=rtrim($media,","); $price = $this->calls_placed[$call]['price']; $status = $this->calls_placed[$call]['status']; $rateinfo = $this->calls_placed[$call]['rateInfo']; $duration = normalizeTime($this->calls_placed[$call]['duration']); $dialURI = $this->PhoneDialURL($uri) ; $htmlDate = $this->colorizeDate($this->calls_placed[$call]['startTime']); $stopTime = $this->calls_placed[$call]['stopTime']; $htmlURI = $this->htmlURI($uri); $urlURI = urlencode($this->normalizeURI($uri)); $sessionId = urlencode($this->calls_placed[$call]['sessionId']); $fromTag = urlencode($this->calls_placed[$call]['fromTag']); $toTag = urlencode($this->calls_placed[$call]['toTag']); $proxyIP = urlencode($this->calls_placed[$call]['proxyIP']); $trace_link = "Server Logs"; if ($price) { $price_print =sprintf(" (%s %s)",$price,$this->currency); } else { $price_print = ''; } $rr=floor($j/2); $mod=$j-$rr*2; if ($mod ==0) { $_class='odd'; } else { $_class='even'; } if (!$stopTime) { $duration = _('In progress'); } print " "; print ""; print ""; print " "; } print "
$htmlDate $dialURI $duration $htmlURI ($media) $price_print$trace_linkurl&tab=contacts&task=add&uri=$urlURI&search_text=$urlURI>$this->phonebook_img
"; } } function getHistory($status = 'all') { dprint("getHistory()"); $fromDate = time() - 3600 * 24 * 14; // last two weeks $toDate = time(); $CallQuery = array( "fromDate" => $fromDate, "toDate" => $toDate, "limit" => 50 ); $CallsQuery = array( "placed" => $CallQuery, "received" => $CallQuery ); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getCalls($this->sipId, $CallsQuery); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf( "

Error (SipPort): %s (%s): %s", $error_msg, $error_fault->detail->exception->errorcode, $error_fault->detail->exception->errorstring ); return false; } // received calls foreach ($result->received as $callStructure) { $media = array(); $apps = explode(",", quoted_printable_decode($callStructure->applicationTypes[0])); foreach ($apps as $app) { $media[] = trim($app); } if (!$callStructure->stopTime && $status == 'completed') { continue; } $fromHeader = quoted_printable_decode($callStructure->fromHeader); $this->calls_received[] = array( "remoteParty" => quoted_printable_decode($callStructure->fromURI), "displayName" => getDisplayNameFromFromHeader($fromHeader), "startTime" => getLocalTime($this->timezone, $callStructure->startTime), "stopTime" => getLocalTime($this->timezone, $callStructure->stopTime), "timezone" => $this->timezone, "duration" => $callStructure->duration, "status" => $callStructure->status, "sessionId" => quoted_printable_decode($callStructure->sessionId), "fromTag" => quoted_printable_decode($callStructure->fromTag), "toTag" => quoted_printable_decode($callStructure->toTag), "proxyIP" => $callStructure->proxyIP, "media" => $media ); } // placed calls foreach ($result->placed as $callStructure) { if ($callStructure->status == 435) continue; $media = array(); $apps = explode(",", quoted_printable_decode($callStructure->applicationTypes[0])); foreach ($apps as $app) { $media[] = trim($app); } if (!$callStructure->stopTime && $status == 'completed') { continue; } $fromHeader = quoted_printable_decode($callStructure->fromHeader); $this->calls_placed[] = array( "remoteParty" => quoted_printable_decode($callStructure->toURI), "displayName" => "", "startTime" => getLocalTime($this->timezone, $callStructure->startTime), "stopTime" => getLocalTime($this->timezone, $callStructure->stopTime), "timezone" => $this->timezone, "duration" => $callStructure->duration, "status" => $callStructure->status, "price" => $callStructure->price, "sessionId" => quoted_printable_decode($callStructure->sessionId), "fromTag" => quoted_printable_decode($callStructure->fromTag), "toTag" => quoted_printable_decode($callStructure->toTag), "proxyIP" => $callStructure->proxyIP, "media" => $media ); } $this->call_history = array( 'placed' => $this->calls_placed, 'received' => $this->calls_received ); } function getCallStatistics() { dprint("getCallStatistics()"); $fromDate = mktime(0, 0, 0, date("m"), "01", date("Y")); $toDate = time(); $CallQuery = array( "fromDate" => $fromDate, "toDate" => $toDate ); $CallQuery = array( "limit" => 1 ); $CallsQuery = array( "placed" => $CallQuery ); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getCallStatistics($this->sipId, $CallsQuery); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf( "

Error (SipPort): %s (%s): %s", $error_msg, $error_fault->detail->exception->errorcode, $error_fault->detail->exception->errorstring ); return false; } //dprint_r($result); $this->thisMonth['calls'] = $result->placed->calls; $this->thisMonth['price'] = $result->placed->price; } function addPhonebookEntry() { dprint("addPhonebookEntry()"); $uri = strtolower(trim($_REQUEST['uri'])); $name = trim($_REQUEST['name']); $group = trim($_REQUEST['group']); if (!strlen($uri)) return false; $phonebookEntry = array( 'uri' => $uri, 'name' => $name, 'group' => $group ); dprint("addPhonebookEntry"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->addPhoneBookEntry($this->sipId, $phonebookEntry); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf( "

Error (SipPort): %s (%s): %s
", $error_msg, $error_fault->detail->exception->errorcode, $error_fault->detail->exception->errorstring ); return false; } return true; } function updatePhonebookEntry() { dprint("updatePhonebookEntry()"); $uri = strtolower(trim($_REQUEST['uri'])); $group = trim($_REQUEST['group']); $name = trim($_REQUEST['name']); $phonebookEntry = array( 'name' => $name, 'uri' => $uri, 'group' => $group ); //dprint_r($phonebookEntry); dprint("updatePhonebookEntry"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->updatePhoneBookEntry($this->sipId, $phonebookEntry); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf( "

Error (SipPort): %s (%s): %s", $error_msg, $error_fault->detail->exception->errorcode, $error_fault->detail->exception->errorstring ); return false; } return true; } function deletePhonebookEntry() { dprint("deletePhonebookEntry()"); $uri = strtolower($_REQUEST['uri']); dprint("deletePhonebookEntry"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->deletePhoneBookEntry($this->sipId, $uri); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf( "

Error (SipPort): %s (%s): %s", $error_msg, $error_fault->detail->exception->errorcode, $error_fault->detail->exception->errorstring ); return false; } return true; } function getPhoneBookEntries() { dprint("getPhoneBookEntries()"); if ($_REQUEST['task'] == 'search') { $search_text = trim($_REQUEST['uri']); } $group = trim($_REQUEST['group']); if (!strlen($search_text)) $search_text="%" ; $match = array( 'uri' => '%'.$search_text.'%', 'name' => '%'.$search_text.'%' ); if (strlen($group)) { if ($group == "empty") { $match['group'] = ''; } else { $match['group'] = $group; } } $range = array( 'start' => 0, 'count' => 100 ); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getPhoneBookEntries($this->sipId, $match, $range); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf( "

Error (SipPort): %s (%s): %s", $error_msg, $error_fault->detail->exception->errorcode, $error_fault->detail->exception->errorstring ); return false; } $this->PhonebookEntries=$result->entries; //dprint_r($this->PhonebookEntries); } function showContactsTab() { dprint("showContactsTab()"); if ($this->show_directory) { $chapter = sprintf(_("Directory")); $this->showChapter($chapter); print "

"; print _("To find other SIP Addresses fill in the First Name or the Last Name and click the Search button. "); print "
"; $this->showSearchDirectory(); print "
"; } if ($this->rows || $_REQUEST['task'] == 'directory') { // hide local contacts if we found a global contact return true; } $chapter = sprintf(_("Don't Disturb")).' '.sprintf(_("Groups")); $this->showChapter($chapter); print "
"; print _("You can organize contacts into groups that can be used to accept incoming calls in Don't Disturb section. "); print "
"; $adminonly = $_REQUEST['adminonly']; $accept = $_REQUEST['accept']; // selected search group; $task = $_REQUEST['task']; //if ($task == "search" ){ $search_text = $_REQUEST['uri']; // } $confirm = $_REQUEST['confirm']; $group = $_REQUEST['group']; $uri = $_REQUEST['uri']; $name = $_REQUEST['name']; if ($task == "deleteContact" && $confirm) { $this->deletePhonebookEntry(); unset($task); unset($confirm); } elseif ($task == "update") { $this->updatePhonebookEntry(); unset($task); } elseif ($task == "add") { $this->addPhonebookEntry(); unset($task); } $this->getPhoneBookEntries(); $maxrowsperpage = 250; $url_string = $this->url."&tab=contacts"; printf( "
", $this->url, $this->url, $this->url, _("Add sip address or search for contacts") ); if (count($this->PhonebookEntries) || $task == "search"){ $selected[$group] = "selected"; printf( " ", $selected['empty'], _("No group"), _("Search") ); } printf( "
%s
", _("Add"), _("(wildcard %)") ); if (count($this->PhonebookEntries)){ print "

"; print ""; print ""; print ""; print ""; foreach (array_keys($this->PhonebookEntries) as $_entry) { $found = $i + 1; $rr = floor($found / 2); $mod = $found - $rr * 2; if ($mod == 0) { $_class = 'odd'; } else { $_class = 'even'; } printf( " %s ", $_class, $found, $this->url, $this->tab, $this->hiddenElements, $this->tab, $this->PhonebookEntries[$_entry]->uri, $found, $this->PhonebookEntries[$_entry]->uri ); if (preg_match("/\%/", $this->PhonebookEntries[$_entry]->uri)) { print ""; if ($task == "deleteContact" && $uri == $this->PhonebookEntries[$_entry]->uri) { print ""; $i++; } print "
"; print ""; print _("SIP Address"); print ""; print ""; print ""; print _("Display Name"); print ""; print _("Group"); print ""; print _("Action"); print "
%s%s"; } else { printf( " %s ", $this->PhoneDialURL($this->PhonebookEntries[$_entry]->uri) ); } printf("
", $this->PhonebookEntries[$_entry]->name); printf("%s
", _("Update")); print "
"; printf( ""; print ""; printf( "", $url_string, urlencode($this->PhonebookEntries[$_entry]->uri), urlencode($search_text) ); print _("Confirm"); } else { print ""; printf( "", $url_string, urlencode($this->PhonebookEntries[$_entry]->uri), urlencode($search_text) ); if ($this->delete_img) { //print $this->delete_img; print ""; } else { print _("Delete"); } } print ""; print "
"; print ""; } } function exportPhonebook($userAgent) { dprint("exportPhonebook()"); $this->getPhonebookEntries(); $this->contentType = "Content-type: text/csv"; if (!is_array($this->PhonebookEntries) || !count($this->PhonebookEntries)) return true; if (!$userAgent) $userAgent = 'snom'; if ($userAgent == 'snom') { $this->export_filename = "tbook.csv"; $phonebook .= sprintf("Name,Address,Group\n"); } elseif ($userAgent == 'eyebeam') { $phonebook .= sprintf("Name,Group Name,SIP URL,Proxy ID\n"); } elseif ($userAgent == 'csco') { $this->contentType = "Content-type: text/xml"; $this->export_filename = "directory.xml"; $phonebook .= sprintf( "\n\t%s\n\tDirectory\n", $this->account ); } elseif ($userAgent == 'unidata') { $this->export_filename = "phonebook.csv"; $phonebook .= sprintf("Index,Name,,,,\n"); $phonebook .= sprintf("0,Undefined,,,,\n"); $z = 1; foreach ($this->PhonebookGroups as $_group) { $this->groupIndex[$_group] = $z; $phonebook .= sprintf("%s,%s,,,,\n", $z, $_group); $z++; } $phonebook .= sprintf("\nIndex,Name,RdNm,Tel,Group\n"); } $found = 0; foreach (array_keys($this->PhonebookEntries) as $_entry) { $fname = $this->PhonebookEntries[$_entry]->firstName; $lname = $this->PhonebookEntries[$_entry]->lastName; $uri = $this->PhonebookEntries[$_entry]->uri; $group = $this->PhonebookEntries[$_entry]->group; if (!preg_match("/[_%]/", $uri)) { $uri = substr($uri, 4); $els = explode("@", $uri); if ($els[1] == $this->domain) $uri=$els[0]; if ($userAgent == 'snom') { $phonebook .= sprintf( "%s %s,%s,%s\n", $fname, $lname, $uri, $this->PhonebookGroups[$group] ); } elseif ($userAgent == 'unidata' && $fname && $lname) { $phonebook .= sprintf( "%s,%s,%s %s,%s,%s\n", $found, $fname, $fname, $lname, $uri, $this->PhonebookGroups[$group] ); } elseif ($userAgent == 'eyebeam') { $phonebook .= sprintf( "%s %s,%s,1\n", $fname, $lname, $this->PhonebookEntries[$_entry]->uri, $this->PhonebookGroups[$group] ); } elseif ($userAgent == 'csco') { $phonebook .= sprintf( "\n\t\n\t%s %s\n\t%s\n\t\n", $fname, $lname, $uri ); } $found++ ; } } if ($userAgent == 'csco') { $phonebook .= sprintf("\n\n"); } Header($this->contentType); $_header = sprintf("Content-Disposition: inline; filename=%s", $this->export_filename); Header($_header); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 header("Pragma: no-cache"); print $phonebook; } function getRejectMembers() { dprint("getRejectMembers()"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getRejectMembers($this->sipId); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf( "

Error (SipPort): %s (%s): %s", $error_msg, $error_fault->detail->exception->errorcode, $error_fault->detail->exception->errorstring ); return false; } $this->rejectMembers = $result; //dprint_r($this->rejectMembers); return true; } function setRejectMembers() { $members = array(); $rejectMembers = $_REQUEST['rejectMembers']; foreach ($rejectMembers as $_member) { if (strlen($_member) && !preg_match("/^sip:/", $_member)) { $_member = 'sip:'.$_member; } if (strlen($_member)) $members[] = $_member; } dprint("setRejectMembers"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->setRejectMembers($this->sipId, $members); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf( "

Error (SipPort): %s (%s): %s", $error_msg, $error_fault->detail->exception->errorcode, $error_fault->detail->exception->errorstring ); return false; } } function getJournalEntries() { $this->journalEntries['success'] = false; $this->journalEntries['error_message'] = NULL; $this->journalEntries['results'] = array(); $return_summary = $_REQUEST['summary']; if ($this->chat_replication_backend == 'mysql') { $this->db = new DB_CDRTool(); $where=""; if ($_REQUEST['except_uuid']) { $where.= sprintf(" and uuid <> '%s'", addslashes($_REQUEST['except_uuid'])); } if ($_REQUEST['after_id']) { $after_id = intval($_REQUEST['after_id']); } else { $after_id = 0; } $where.= sprintf(" and id > %d", addslashes($after_id)); if ($_REQUEST['after_timestamp']) { $where.= sprintf(" and timestamp > '%s'", addslashes($_REQUEST['after_timestamp'])); } if ($_REQUEST['limit'] and intval($_REQUEST['limit']) < 5000) { $limit = intval($limit); } else { $limit = 5000; } $query=sprintf("select * from client_journal where account = '%s' %s order by timestamp ASC limit %d", addslashes($this->account), $where, $limit); if (!$this->db->query($query)) { $this->journalEntries['error_message'] = 'Database Failure'; $this->journalEntries['rows'] = 0; return false; } else { $this->journalEntries['success'] = true; $this->journalEntries['rows'] = $this->db->num_rows(); } if ($this->db->num_rows()) { while ($this->db->next_record()) { $entry = array( 'id' => $this->db->f('id'), 'source' => 'default', 'timestamp' => $this->db->f('timestamp'), 'account' => $this->db->f('account'), 'uuid' => $this->db->f('uuid'), 'ip_address' => $this->db->f('ip_address'), 'data' => $this->db->f('data') ); $this->journalEntries['results'][]=$entry; } } - } else { - if (!$this->getMongoJournalTable()) { - $result['success'] = false; - $result['error_message'] = $this->mongo_exception; - return $result; - } - - $mongo_where=array(); - $mongo_where['account'] = $this->account; - if ($_REQUEST['except_uuid']) { - $mongo_where['uuid'] = array('$ne' => $_REQUEST['except_uuid']); - } - - if ($_REQUEST['after_timestamp']) { - $mongo_where['timestamp'] = array('$gt' => intval($_REQUEST['after_timestamp'])); - } - - if ($_REQUEST['limit'] and intval($_REQUEST['limit']) < 5000) { - $limit = intval($limit); - } else { - $limit = 5000; - } - - $cursor = $this->mongo_table_ro->find($mongo_where)->sort(array('timestamp'=>1))->limit($limit)->slaveOkay(); - $this->journalEntries['success'] = true; - $this->journalEntries['rows'] = $cursor->count(); - - foreach ($cursor as $result) { - $entry = array( - 'id' => strval($result['_id']), - 'source' => 'default', - 'timestamp' => $result['timestamp'], - 'account' => $result['account'], - 'uuid' => $result['uuid'], - 'ip_address' => $result['ip_address'], - 'data' => $result['data'] - ); - $this->journalEntries['results'][]=$entry; - } - - if ($return_summary) { - $mongo_where=array(); - $mongo_where['account'] = $this->account; - if ($_REQUEST['except_uuid']) { - $mongo_where['uuid'] = array('$ne' => $_REQUEST['except_uuid']); - } - - if ($_REQUEST['limit'] and intval($_REQUEST['limit']) < 5000) { - $limit = intval($limit); - } else { - $limit = 5000; - } - - $cursor = $this->mongo_table_ro->find($mongo_where)->sort(array('timestamp'=>1))->limit($limit)->slaveOkay(); - foreach ($cursor as $result) { - $entry = array( - 'journal_id' => strval($result['_id']), - 'timestamp' => $result['timestamp'], - ); - $this->journalEntries['summary'][]=$entry; - } - } } return True; } function putJournalEntries() { $result['results'] = array(); if (strlen($_REQUEST['uuid'])) { $uuid = $_REQUEST['uuid']; } else { $result['success'] = false; $result['error_message'] = 'Missing uuid'; return $result; } if (strlen($_REQUEST['data'])) { $data = $_REQUEST['data']; } else { $result['success'] = false; $result['error_message'] = 'Missing data'; return $result; } if ($this->chat_replication_backend == 'mysql') { $this->db = new DB_CDRTool(); - } else if ($this->chat_replication_backend == 'mongo') { - if (!$this->getMongoJournalTable()) { - $result['success'] = false; - $result['error_message'] = $this->mongo_exception; - return $result; - } } if ($rows=json_decode($data)) { foreach ($rows as $row) { if (!property_exists($row, 'data')) { continue; } $entry = $row->data; if (property_exists($row, 'action')) { $action = $row->action; } else { $action = 'add'; } if ($this->chat_replication_backend == 'mysql') { $query=sprintf("insert into client_journal (timestamp, account, uuid, data, ip_address) values (NOW(),'%s', '%s', '%s', '%s')", addslashes($this->account), addslashes($uuid), addslashes($entry), addslashes($_SERVER['REMOTE_ADDR'])); if (!$this->db->query($query)) { $result['results'][]=array('id' => $row->id, 'journal_id' => NULL, 'source' => 'default' ); } else { $query="select LAST_INSERT_ID() as id"; $this->db->query($query); $this->db->next_record(); $id = $this->db->f('id'); $result['results'][]=array('id' => $row->id, 'journal_id' => $id, 'source' => 'default' ); } - } else if ($this->chat_replication_backend == 'mongo') { - if ($action == 'add') { - $timestamp = time(); - $mongo_query=array('timestamp' => $timestamp, - 'datetime' => Date("Y-m-d H:i:s", $timestamp), - 'account' => $this->account, - 'uuid' => $uuid, - 'data' => $entry, - 'ip_address' => $_SERVER['REMOTE_ADDR'] - ); - - $this->mongo_table_rw->insert($mongo_query); - if ($mongo_query['_id']) { - $mongo_id = strval($mongo_query['_id']); - $result['results'][]=array('id' => $row->id, - 'journal_id' => $mongo_id, - 'source' => 'default' - ); - } else { - $result['results'][]=array('id' => $row->id, - 'journal_id' => NULL, - 'source' => 'default' - ); - } - } else if ($action == 'remove') { - if (property_exists($row, 'journal_id')) { - $mongo_query=array( - 'account' => $this->account, - 'journal_id' => $row->journal_id - ); - - $this->mongo_table_rw->remove($mongo_query); - $result['results'][]=array('id' => NULL, - 'journal_id' => $row->journal_id - ); - } - } } } $result['success'] = true; } else { $result['success'] = false; $result['error_message'] = 'Json decode error'; } return $result; } function deleteJournalEntries() { if (strlen($_REQUEST['data'])) { $data = $_REQUEST['data']; $entries = json_decode($data); } else { if (strlen($_REQUEST['journal_id'])) { $entries=array($_REQUEST['journal_id']); } else { $result['success'] = false; $result['error_message'] = 'Missing data'; return $result; } } if ($this->chat_replication_backend == 'mysql') { $this->db = new DB_CDRTool(); - } else if ($this->chat_replication_backend == 'mongo') { - if (!$this->getMongoJournalTable()) { - $result['success'] = false; - $result['error_message'] = $this->mongo_exception; - return $result; - } } if ($entries) { if ($this->chat_replication_backend == 'mysql') { $journal_id_sql=""; foreach ($entries as $entry) { $journal_id_sql.=sprintf("'%s',",$entry); } $journal_id_sql = rtrim($journal_id_sql,","); $query=sprintf("delete from client_journal where account in '%s' and journal_id in (%s)", addslashes($this->account), addslashes($journal_id_sql)); if (!$this->db->query($query)) { $result['error_message'] = 'database error'; } else { $result['success'] = true; } - - } else if ($this->chat_replication_backend == 'mongo') { - $id_entries=array(); - foreach ($entries as $entry) { - $id_entries[] = new MongoId($entry); - } - $mongo_query=array('account' => $this->account, - '_id' => array('$in'=> $id_entries) - ); - - $this->mongo_table_rw->remove($mongo_query); - $result['success'] = true; } } else { $result['success'] = false; $result['error_message'] = 'No journal entries provided'; } return $result; } function getAcceptRules() { dprint("getAcceptRules()"); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->getAcceptRules($this->sipId); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } foreach(array_keys($result->rules->persistent) as $_rule) { $_key=$result->rules->persistent[$_rule]->days; $this->acceptRules['persistent'][$_key]=array('start' =>$result->rules->persistent[$_rule]->start, 'stop' =>$result->rules->persistent[$_rule]->stop, 'groups'=>$result->rules->persistent[$_rule]->groups); } $this->acceptRules['temporary']=array('groups' => $result->rules->temporary->groups, 'duration'=> $result->rules->temporary->duration ); $this->acceptRules['groups'] = $result->nonEmptyGroups; //dprint_r($this->acceptRules); return true; } function setAcceptRules() { dprint("setAcceptRules()"); $persistentAcceptArray=array(); $temporaryAcceptArray=array(); foreach (array_keys($this->acceptDailyProfiles) as $profile) { unset($groups); $radio_persistentVarName='radio_persistent_'.$profile; $radio_persistent=$_REQUEST[$radio_persistentVarName]; if ($radio_persistent=="0") { $groups[]='everybody'; } else if ($radio_persistent=="1") { $groups[]='nobody'; } else if ($radio_persistent=="2") { $groupsVarName='groups_'.$profile; $groups=$_REQUEST[$groupsVarName]; } $startVarName='start_'.$profile; $start=$_REQUEST[$startVarName]; $stopVarName='stop_'.$profile; $stop=$_REQUEST[$stopVarName]; if (!preg_match("/^[0-2][0-9]:[0-5][0-9]$/",$start) || !preg_match("/^[0-2][0-9]:[0-5][0-9]$/",$stop) || ($start=="00:00" && $stop=="00:00") || !$start || !$stop || ($radio_persistent=="2" && (!is_array($groups) || !count($groups) )) ) { continue; } $persistentAcceptArray[]=array('start' => $start, 'stop' => $stop, 'groups' => $groups, 'days' => intval($profile) ); } // temporary $radio_temporary=$_REQUEST['radio_temporary']; unset($groups_temporary); if ($radio_temporary=="0") { $groups_temporary[]='everybody'; } else if ($radio_temporary=="1") { $groups_temporary[]='nobody'; } else if ($radio_temporary=="2") { $groups_temporary=$_REQUEST['groups_temporary']; } if (!is_array($groups_temporary)) $groups_temporary=array(); $duration=$_REQUEST['duration']; $temporaryAccept=array("groups" => $groups_temporary, "duration"=> intval($duration) ); // combine persistent and temporary $rules=array("persistent" =>$persistentAcceptArray, "temporary" =>$temporaryAccept); $this->SipPort->addHeader($this->SoapAuth); $result = $this->SipPort->setAcceptRules($this->sipId,$rules); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } return true; } function showAcceptTab() { if (in_array("trunking",$this->groups)) { return false; } $chapter=sprintf(_("Do Not Disturb")); $this->showChapter($chapter); $this->getAcceptRules(); $this->getVoicemail(); $this->getDivertTargets(); $this->getDiversions(); print "

"; print "

"; print _("You can reject calls depending on the time of day and Caller-ID. "); print _("You can create custom groups in the Contacts page like Family or Coworkers. "); print "

"; print _("Rejected calls are diverted based on the Unavailable condition in the Call Forwarding page. "); print "

"; print "

"; printf (_("Your current time is: %s"),$this->timezone); $timestamp=time(); $LocalTime=getLocalTime($this->timezone,$timestamp); print " $LocalTime"; print "

"; // $chapter=sprintf(_("Rules")); // $this->showChapter($chapter); /* print "
"; print _("This will override the permanent rules for the chosen duration. "); print "
"; */ if ($this->acceptRules['temporary']['duration']) { $class_e='error'; } else { $class_e=''; } // print "
// //"; // print ""; // print _("minute(s)"); // print ""; //print "
//
//"; $chapter=sprintf(_("Rules")); $this->showChapter($chapter); print "
"; print ""; print ""; print ""; $_name="radio_temporary"; $_checked_everybody=""; $_checked_nobody=""; $_checked_groups=""; if (is_array($this->acceptRules['temporary']['groups']) &&in_array("everybody",$this->acceptRules['temporary']['groups'])) { $_checked_everybody="checked"; } else if (is_array($this->acceptRules['temporary']['groups']) && in_array("nobody",$this->acceptRules['temporary']['groups'])) { $_checked_nobody="checked"; } else if (!in_array('everybody',$this->acceptRules['temporary']['groups']) && !in_array('nobody',$this->acceptRules['temporary']['groups']) && count($this->acceptRules['temporary']['groups'])) { $_checked_groups="checked"; } if ($_checked_nobody) { $class_nobody="checked_groups"; } else { $class_nobody="note"; } printf (" ",$_name,$_checked_everybody,_("Everybody")); printf ("",$_name,$_checked_nobody,_("Nobody")); $c=count($this->acceptRules['groups']); if ($_checked_groups) { $class_groups="checked_groups"; } else { $class_groups="note"; } print ""; print " "; foreach (array_keys($this->acceptDailyProfiles) as $profile) { if ($this->acceptRules['persistent'][$profile]['start'] || $this->acceptRules['persistent'][$profile]['stop']) { $class="checked_groups"; $class2="label label-info"; } else { $class="mhj"; $class2=''; } if ($profile==1) { print ""; } print " "; unset($selected_StartTime); $selected_StartTime[$this->acceptRules['persistent'][$profile]['start']]="selected"; printf ("",$_name,$_checked_everybody,_("Everybody")); printf ("",$_name,$_checked_nobody,_("Nobody")); $c=count($this->acceptRules['groups']); if ($_checked_groups) { $class_groups="checked_groups"; } else { $class_groups="note"; } print " "; } print "
"; print _("Temporary"); print "
"; print _("Duration"); print ""; if ($this->acceptRules['temporary']['duration']) { printf (' ',$this->acceptRules['temporary']['duration']); print " acceptRules['temporary']['duration']; print "\" disabled=true>"; print " acceptRules['temporary']['duration']; print "\"> "; } else { print " "; print _("Minute(s)"); print ""; } print " %s %s "; if (count($this->acceptRules['groups'])>2) { printf ("",$_name,$_checked_groups); $i=0; foreach(array_keys($this->acceptRules['groups']) as $_group) { $i++; if (preg_match("/(everybody|nobody)/",$this->acceptRules['groups'][$_group])) continue; if (in_array($this->acceptRules['groups'][$_group],$this->acceptRules['temporary']['groups'])) { $_checked="checked"; } else { $_checked=""; } $_name="groups_temporary[]"; printf (" %s\n", $_name, $this->acceptRules['groups'][$_group], $_checked, $this->PhonebookGroups[$this->acceptRules['groups'][$_group]] ); } } print "
"; print _("Permanent"); print "
"; print _("Days"); print " "; print _("Time Interval"); print " "; print _("Groups"); print "
"; printf ("%s",$this->acceptDailyProfiles[$profile]); print ""; unset($selected_StopTime); $selected_StopTime[$this->acceptRules['persistent'][$profile]['stop']]="selected"; printf (""; $_name="radio_persistent_".$profile; $_checked_everybody=""; $_checked_nobody=""; $_checked_groups=""; if (is_array($this->acceptRules['persistent'][$profile]['groups']) && in_array("everybody",$this->acceptRules['persistent'][$profile]['groups'])) { $_checked_everybody="checked"; } else if (is_array($this->acceptRules['persistent'][$profile]['groups']) && in_array("nobody",$this->acceptRules['persistent'][$profile]['groups'])) { $_checked_nobody="checked"; } else if (!in_array('everybody',$this->acceptRules['persistent'][$profile]['groups']) && !in_array('nobody',$this->acceptRules['persistent'][$profile]['groups']) && count($this->acceptRules['persistent'][$profile]['groups'])) { $_checked_groups="checked"; } else { $_checked_everybody="checked"; } if ($_checked_nobody) { $class_nobody="checked_groups"; } else { $class_nobody="note"; } printf (" %s %s"; if (count($this->acceptRules['groups'])>2) { printf ("",$_name,$_checked_groups); $i=0; foreach(array_keys($this->acceptRules['groups']) as $_group) { $i++; if (preg_match("/(everybody|nobody)/",$this->acceptRules['groups'][$_group])) continue; if (in_array($this->acceptRules['groups'][$_group],$this->acceptRules['persistent'][$profile]['groups'])) { $_checked="checked"; } else { $_checked=""; } $_name="groups_".$profile."[]"; printf (" %s ", $_name, $this->acceptRules['groups'][$_group], $profile, $_checked, $this->PhonebookGroups[$this->acceptRules['groups'][$_group]] ); } } print "
"; print "
"; print " "; print "
"; print $this->hiddenElements; print " "; $chapter=sprintf(_("Rejected Callers")); $this->showChapter($chapter); print "
"; print "
"; print _("Use %Number@% to match PSTN numbers and user@domain to match SIP Addresses"); print "
"; if ($this->getRejectMembers()) { foreach ($this->rejectMembers as $_member) { $j++; $rr=floor($j/2); $mod=$j-$rr*2; if ($mod ==0) { $_class='odd'; } else { $_class='even'; } print "
"; print ""; print "
"; print "
"; } } print "
"; print ""; print "
"; print "
"; print "
"; print " "; print "
"; print " "; print $this->hiddenElements; print " "; } function deleteAccount($skip_html=False) { dprint ("SipSettings->deleteAccount($this->account, $this->email)"); $this->getBalanceHistory(); if (count($this->balance_history) != "0" && $this->login_type == 'subscriber') { return false; } if (!$this->email && !$skip_html) { print "

"; print _("Please fill in the e-mail address. "); print ""; return false; } $subject = sprintf("Removal of SIP account %s",$this->account); //$this->expire_date = new DateTime('now'); $this->expire_date = date("Y-m-d H:i:s",strtotime("+2 days")); $this->ip = $_SERVER['REMOTE_ADDR']; $tpl_html = $this->getEmailDeleteTemplateHTML($this->reseller, $this->Preferences['language']); //dprint("$tpl_html"); if (!$tpl_html && !$skip_html) { print "

"; print _("Error: no HTML email template found"); print ""; return false; } //print "$tpl_html"; define("SMARTY_DIR", "/usr/share/php/smarty/libs/"); include_once(SMARTY_DIR . 'Smarty.class.php'); $smarty = new Smarty; $smarty->template_dir = '.'; //$smarty->use_sub_dirs = true; //$smarty->cache_dir = 'templates_c'; $smarty->assign('client', $this); //print"$this->sip_settings_page"; if ($tpl_html) { $bodyhtml = $smarty->fetch($tpl_html); } include_once 'Mail.php'; include_once 'Mail/mime.php' ; $hdrs = array( 'From' => $this->support_email, 'Subject' => $subject, // 'Cc' => $this->support_email ); //dprint("1"); $crlf = "\n"; $mime = new Mail_mime($crlf); if ($tpl_html) { $mime->setHTMLBody($bodyhtml); } $body = $mime->get(); $hdrs = $mime->headers($hdrs); $mail =& Mail::factory('mail'); if ($mail->send($this->email, $hdrs, $body)) { if (!$skip_html) { $this->Preferences['account_delete_request']=1; $this->saveSettings(); $this->getAccount($this->account); print "

"; printf (_("Removal email has been sent to %s"), $this->email); } return 1; } } function sendEmail($skip_html=False) { dprint ("SipSettings->sendEmail($this->email)"); $this->getVoicemail(); $this->getEnumMappings(); $this->getAliases(); $this->countAliases=count($this->aliases); if (!$this->email && !$skip_html) { print "

"; print _("Please fill in the e-mail address. "); print ""; return false; } $subject = sprintf("SIP Account settings %s",$this->account); //if ($_REQUEST['sip_filter'] == '1') { // $identifier = $this->RandomIdentifier(); //} $tpl = $this->getEmailTemplate($this->reseller, $this->Preferences['language']); if (!$tpl && !$skip_html) { print "

"; print _("Error: no email template found"); print ""; return false; } $tpl_html = $this->getEmailTemplateHTML($this->reseller, $this->Preferences['language']); //if (!$tpl_html && !$skip_html) { // print "

"; // print _("Error: no HTML email template found"); // print ""; //} if (!$this->store_clear_text_password) { $web_password = ''; } if (in_array("free-pstn",$this->groups)) $this->allowPSTN=1; // used by smarty define("SMARTY_DIR", "/usr/share/php/smarty/libs/"); include_once(SMARTY_DIR . 'Smarty.class.php'); $smarty = new Smarty; $smarty->template_dir = '.'; //$smarty->use_sub_dirs = true; //$smarty->cache_dir = 'templates_c'; $smarty->assign('client', $this); $bodyt = $smarty->fetch($tpl); if ($tpl_html) { $bodyhtml = $smarty->fetch($tpl_html); } include_once 'Mail.php'; include_once 'Mail/mime.php' ; $hdrs = array( 'From' => $this->support_email, 'Subject' => $subject ); $crlf = "\n"; $mime = new Mail_mime($crlf); $mime->setTXTBody($bodyt); if ($tpl_html) { $mime->setHTMLBody($bodyhtml); } $body = $mime->get(); $hdrs = $mime->headers($hdrs); $mail =& Mail::factory('mail'); //dprint_r($_REQUEST); if ($mail->send($this->email, $hdrs, $body)) { if (!$skip_html) { print "

"; printf (_("SIP settings have been sent to %s"), $this->email); } if ($_REQUEST['password_reset'] == 'on') { $this->sendPasswordReset($skip_html); } return 1; } } function sendChangedEmail($skip_html=False, $fields=array()) { dprint ("SipSettings->sendChangedEmail($this->email)"); //dprint_r($fields); $this->ip = $_SERVER['REMOTE_ADDR']; if (!$this->email && !$skip_html) { print "

"; print _("Please fill in the e-mail address. "); print ""; return false; } //$this->location = "Unknown"; $_loc=geoip_record_by_name($_SERVER['REMOTE_ADDR']); if ($_loc['country_name']) { $this->location = $_loc['country_name']; } $subject = sprintf("SIP Account %s changed",$this->account); $tpl = $this->getChangedEmailTemplate($this->reseller, $this->Preferences['language']); if (!$tpl && !$skip_html) { print "

"; print _("Error: no email template found"); print ""; return false; } $tpl_html = $this->getChangedEmailTemplateHTML($this->reseller, $this->Preferences['language']); define("SMARTY_DIR", "/usr/share/php/smarty/libs/"); include_once(SMARTY_DIR . 'Smarty.class.php'); $smarty = new Smarty; $smarty->template_dir = '.'; //$smarty->use_sub_dirs = true; //$smarty->cache_dir = 'templates_c'; $this->fields = $fields; $smarty->assign('client', $this); $bodyt = $smarty->fetch($tpl); if ($tpl_html) { $bodyhtml = $smarty->fetch($tpl_html); } include_once 'Mail.php'; include_once 'Mail/mime.php' ; $hdrs = array( 'From' => $this->support_email, 'Subject' => $subject ); $crlf = "\n"; $mime = new Mail_mime($crlf); $mime->setTXTBody($bodyt); if ($tpl_html) { $mime->setHTMLBody($bodyhtml); } $body = $mime->get(); $hdrs = $mime->headers($hdrs); $mail =& Mail::factory('mail'); //dprint_r($_REQUEST); if ($mail->send($this->email, $hdrs, $body)) { return 1; } } function sendRemoveAccount() { $this->ip = $_SERVER['REMOTE_ADDR']; $subject=sprintf ("The account %s was removed from IP Address: %s",$this->account, $this->ip); syslog(LOG_NOTICE, $subject); } function sendPasswordReset($skip_html=False) { dprint ("SipSettings->sendPasswordEmail($this->email)"); $identifier = RandomIdentifier(); $this->db = new DB_CDRTool(); $this->ip = $_SERVER['REMOTE_ADDR']; $insert_data = array ( 'sip_account' => $this->account, 'email' => $this->email, 'ip' => $this->ip ); $this->expire=date("Y-m-d H:i:s",strtotime("+30 minutes")); $query=sprintf("insert into memcache set `key`='email_%s', `value`='%s', `expire`='%s'", $identifier, json_encode($insert_data), $this->expire ); $this->db->query($query); $this->identifier = $identifier; dprint("$query
Identifier: $identifier"); if (!$this->email && !$skip_html) { print "

"; print _("Please fill in the e-mail address. "); print ""; return false; } $subject = sprintf("Password reset for %s",$this->account); $tpl_html = $this->getEmailPasswordTemplateHTML($this->reseller, $this->Preferences['language']); define("SMARTY_DIR", "/usr/share/php/smarty/libs/"); include_once(SMARTY_DIR . 'Smarty.class.php'); $smarty = new Smarty; $smarty->template_dir = '.'; //$smarty->use_sub_dirs = true; //$smarty->cache_dir = 'templates_c'; $smarty->assign('client', $this); $bodyhtml = $smarty->fetch($tpl_html); include_once 'Mail.php'; include_once 'Mail/mime.php' ; $hdrs = array( 'From' => $this->support_email, 'Subject' => $subject ); $crlf = "\n"; $mime = new Mail_mime($crlf); $mime->setHTMLBody($bodyhtml); $body = $mime->get(); $hdrs = $mime->headers($hdrs); $mail =& Mail::factory('mail'); //dprint_r($_REQUEST); if ($mail->send($this->email, $hdrs, $body) && !$skip_html) { print "

  • "; printf (_("Password reset has been sent to %s"), $this->email); print "
  • "; } return 1; } function checkSettings() { dprint ("checkSettings()"); foreach ($this->form_elements as $el) { ${$el}=trim($_REQUEST[$el]); } if ($accept_temporary_remain && !is_numeric($accept_temporary_remain)) { $this->error=_("Invalid Expiration Period"); return false; } if ($quota && !is_numeric($quota) && !is_float($quota)) { $this->error=_("Invalid Quota"); return false; } if (!$timezone && !$this->timezone) { $this->error=_("Missing Timezone"); return false; } if (!$this->checkEmail($mailto)) { $this->error=_("Invalid E-mail Address"); return false; } $rpid=preg_replace("/[^0-9\x]/","",$rpid); if (preg_match("/^0+([1-9]\d*)$/",$rpid,$m)) $rpid=$m[1]; $quickdial=preg_replace("/[^0-9]/","",$quickdial); if (!strlen($accept_temporary_group)) $accept_temporary_remain=0; if (!$accept_temporary_remain) $accept_temporary_group=""; if (!$anonymous) $anonymous="0"; return true; } function RandomPassword($len=6) { $alf=array("1","2","3","4","5","6","7","8","9"); $i=0; while($i < $len) { srand((double)microtime(true)*1000000); $randval = rand(0,8); $string="$string"."$alf[$randval]"; $i++; } return $string; } function cleanURI($uri) { $uri=preg_replace("/.*sips?:([^;><=]+).*/", "\$1", $uri); return urlencode($uri); } function showUpgradeTab () { } function PhoneDialURL($uri) { $uri=$this->normalizeURI($uri); if (!preg_match("/^sip:/",$uri)) { $uri="sip:".$uri; } $uri_print="$this->call_img"; return $uri_print; } function showChapter($chapter) { print "

    "; print $chapter; print "

    "; } function normalizeURI($uri) { $uri=quoted_printable_decode($uri); $uri=preg_replace("/.*(sips?:[^;><=]+).*/", "\$1", $uri); if (preg_match("/^(sips?:.*):/", $uri, $m)) $uri=$m[1]; if (preg_match("/^(.*sips?:0\d+)@(.*)(>?)$/",$uri,$m)) { $uri=$m[1]."@".$this->domain.$m[3]; } return $uri; } function htmlURI($uri) { if (preg_match("/^sips?:00(\d+)@/",$uri,$m)) { $uri="+".$m[1]; } return htmlentities($uri); } function colorizeDate($call_date) { list($date,$time)=explode(" ",$call_date); if ($date== Date("Y-m-d",time())) { $datePrint="".sprintf(_("Today"))." ".$time; } else if ($date== Date("Y-m-d",time()-3600*24)) { $datePrint="".sprintf(_("Yesterday"))." ".$time; } else { $datePrint=$call_date; } return $datePrint; } function checkEmail($email) { dprint ("checkEmail($email)"); $regexp = "/^([a-z0-9][a-z0-9_.-]*)@([a-z0-9][a-z0-9-]*\.)+([a-z]{2,})$/i"; if (stristr($email,"-.") || !preg_match($regexp, $email)) { return false; } return true; } function getFileTemplate($name, $type="file") { dprint("getFileTemplate(name=$name, type=$type, path=$this->templates_path)"); if ($type=='logo') { $extensions=array('png','gif','jpg'); foreach ($extensions as $_ext) { $file=$this->templates_path.'/'.$this->reseller.'/'.$name.'.'.$_ext; if (file_exists($file)) { return $file; } } foreach ($extensions as $_ext) { if (file_exists("$this->templates_path/default/$name.$_ext")) { return "$this->templates_path/default/$name.$_ext"; } } return false; } else { if (file_exists("$this->templates_path/$this->reseller/$name")) { return "$this->templates_path/$this->reseller/$name"; } elseif (file_exists("$this->templates_path/default/$name")) { return "$this->templates_path/default/$name"; } else { return false; } } } function getEmailTemplate($reseller, $language='en') { $file = "sip_settings_email_$language.tpl"; $file2 = "sip_settings_email.tpl"; //print("templates_path = $this->templates_path"); if (file_exists("$this->templates_path/$this->reseller/$file")) { return "$this->templates_path/$this->reseller/$file"; } elseif (file_exists("$this->templates_path/$this->reseller/$file2")) { return "$this->templates_path/$this->reseller/$file2"; } elseif (file_exists("$this->templates_path/default/$file")) { return "$this->templates_path/default/$file"; } elseif (file_exists("$this->templates_path/default/$file2")) { return "$this->templates_path/default/$file2"; } else { return false; } } function getEmailTemplateHTML($reseller, $language='en') { $file = "sip_settings_email_$language.html.tpl"; $file2 = "sip_settings_email.html.tpl"; //print("templates_path = $this->templates_path"); if (file_exists("$this->templates_path/$this->reseller/$file")) { return "$this->templates_path/$this->reseller/$file"; } elseif (file_exists("$this->templates_path/$this->reseller/$file2")) { return "$this->templates_path/$this->reseller/$file2"; } elseif (file_exists("$this->templates_path/default/$file")) { return "$this->templates_path/default/$file"; } elseif (file_exists("$this->templates_path/default/$file2")) { return "$this->templates_path/default/$file2"; } else { return false; } } function getChangedEmailTemplate($reseller, $language='en') { $file = "sip_settings_changed_$language.tpl"; $file2 = "sip_settings_changed.tpl"; //print("templates_path = $this->templates_path"); if (file_exists("$this->templates_path/$this->reseller/$file")) { return "$this->templates_path/$this->reseller/$file"; } elseif (file_exists("$this->templates_path/$this->reseller/$file2")) { return "$this->templates_path/$this->reseller/$file2"; } elseif (file_exists("$this->templates_path/default/$file")) { return "$this->templates_path/default/$file"; } elseif (file_exists("$this->templates_path/default/$file2")) { return "$this->templates_path/default/$file2"; } else { return false; } } function getChangedEmailTemplateHTML($reseller, $language='en') { $file = "sip_settings_changed_$language.html.tpl"; $file2 = "sip_settings_changed.html.tpl"; //print("templates_path = $this->templates_path"); if (file_exists("$this->templates_path/$this->reseller/$file")) { return "$this->templates_path/$this->reseller/$file"; } elseif (file_exists("$this->templates_path/$this->reseller/$file2")) { return "$this->templates_path/$this->reseller/$file2"; } elseif (file_exists("$this->templates_path/default/$file")) { return "$this->templates_path/default/$file"; } elseif (file_exists("$this->templates_path/default/$file2")) { return "$this->templates_path/default/$file2"; } else { return false; } } function getEmailPasswordTemplateHTML($reseller, $language='en') { $file = "password_reminder_$language.html.tpl"; $file2 = "password_reminder.html.tpl"; //print("templates_path = $this->templates_path"); if (file_exists("$this->templates_path/$this->reseller/$file")) { return "$this->templates_path/$this->reseller/$file"; } elseif (file_exists("$this->templates_path/$this->reseller/$file2")) { return "$this->templates_path/$this->reseller/$file2"; } elseif (file_exists("$this->templates_path/default/$file")) { return "$this->templates_path/default/$file"; } elseif (file_exists("$this->templates_path/default/$file2")) { return "$this->templates_path/default/$file2"; } else { return false; } } function getEmailDeleteTemplateHTML($reseller, $language='en') { $file = "delete_$language.html.tpl"; $file2 = "delete.html.tpl"; //print("templates_path = $this->templates_path"); if (file_exists("$this->templates_path/$this->reseller/$file")) { return "$this->templates_path/$this->reseller/$file"; } elseif (file_exists("$this->templates_path/$this->reseller/$file2")) { return "$this->templates_path/$this->reseller/$file2"; } elseif (file_exists("$this->templates_path/default/$file")) { return "$this->templates_path/default/$file"; } elseif (file_exists("$this->templates_path/default/$file2")) { return "$this->templates_path/default/$file2"; } else { return false; } } function getBillingProfiles() { dprint("getBillingProfiles()"); // Get getBillingProfiles $this->RatingPort->addHeader($this->SoapAuthRating); $result = $this->RatingPort->getEntityProfiles("subscriber://".$this->account); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); if ($error_fault->detail->exception->errorcode != "4001") { printf ("

    Error (Rating): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } } $this->billingProfiles=$result; } function showBillingProfiles() { if ($this->login_type != 'reseller' && $this->login_type != 'admin') { return false; } if (!$this->pstn_changes_allowed) { return false; } $this->getBillingProfiles(); $chapter=sprintf(_("Billing Profiles")); $this->showChapter($chapter); print "

    / ", $this->billingProfiles->profileWeekday, $this->billingProfiles->profileWeekdayAlt ); print "
    "; print "
    / ", $this->billingProfiles->profileWeekend, $this->billingProfiles->profileWeekendAlt ); print "
    "; print "
    "); if ($this->billingProfiles->timezone) { $_timezone=$this->billingProfiles->timezone; } else { $_timezone=$this->resellerProperties['timezone']; } $this->showTimezones('profileTimezone',$_timezone); print "
    "; } function updateBillingProfiles() { if ($this->login_type != 'reseller' && $this->login_type != 'admin') { return false; } if (!$this->pstn_changes_allowed) { return true; } $this->RatingPort->addHeader($this->SoapAuthRating); $result = $this->RatingPort->getEntityProfiles("subscriber://".$this->account); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); if ($error_fault->detail->exception->errorcode != "4001") { printf ("

    Error (Rating): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } } $this->billingProfiles=$result; $profiles=array("entity" =>'subscriber://'.$this->account , "profileWeekday" => trim($_REQUEST['profileWeekday']), "profileWeekdayAlt" => trim($_REQUEST['profileWeekdayAlt']), "profileWeekend" => trim($_REQUEST['profileWeekend']), "profileWeekendAlt" => trim($_REQUEST['profileWeekendAlt']), "timezone" => trim($_REQUEST['profileTimezone']) ); //print_r($profiles); $this->RatingPort->addHeader($this->SoapAuthRating); if ($this->billingProfiles->profileWeekday && !$profiles['profileWeekday']) { // delete profile $result = $this->RatingPort->deleteEntityProfiles('subscriber://'.$this->account); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); if ($error_fault->detail->exception->errorcode != "4001") { printf ("

    Error (Rating): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } } } else if ($profiles['profileWeekday']) { // update profile $result = $this->RatingPort->setEntityProfiles($profiles); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); if ($error_fault->detail->exception->errorcode != "4001") { printf ("

    Error (Rating): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } } } } function getImageForUserAgent($agent) { // array with mappings between User Agents and images foreach ($this->userAgentImages as $agentRegexp => $image) { if (preg_match("/$agentRegexp/i", $agent)) { return $image; } } return "unknown.png"; } function showExtraGroups () { if ($this->disable_extra_groups) return true; $foundGroupInAvailableGroups=array(); foreach ($this->groups as $_grp) { foreach (array_keys($this->availableGroups) as $a_grp) { if ($_grp == $a_grp) $foundGroupInAvailableGroups[]=$_grp; continue; } } $extraGroups = array_unique(array_diff($this->groups,$foundGroupInAvailableGroups)); foreach ($extraGroups as $_eg) { $extraGroups_text.=$_eg.' '; } if ($this->login_type == 'subscriber') { printf ("",trim($extraGroups_text)); } else { print "

    "; printf ("",trim($extraGroups_text)); print "
    "; } } function generateCertificate() { global $enrollment; include("/etc/cdrtool/enrollment/config.ini"); if (!is_array($enrollment)) { print _("Error: missing enrollment settings"); return false; } if (!$enrollment['ca_conf']) { //print _("Error: missing enrollment ca_conf settings"); return false; } if (!$this->owner) { return false; } if (!$enrollment['ca_crt']) { //print _("Error: missing enrollment ca_crt settings"); return false; } if (!$enrollment['ca_key']) { //print _("Error: missing enrollment ca_key settings"); return false; } $config = array( 'config' => $enrollment['ca_conf'], 'digest_alg' => 'md5', 'private_key_bits' => 1024, 'private_key_type' => OPENSSL_KEYTYPE_RSA, 'encrypt_key' => false, ); $dn = array( "countryName" => "NL", "stateOrProvinceName" => "Noord Holland", "localityName" => "Haarlem", "organizationName" => "AG Projects", "organizationalUnitName" => "Blink", "commonName" => $this->owner, "emailAddress" => $this->email ); $this->key = openssl_pkey_new($config); if ($this->key==FALSE) { while (($e = openssl_error_string()) !== false) { echo $e . "\n"; print "

    "; } return false; } $this->csr = openssl_csr_new($dn, $this->key); if (!$this->csr) { while (($e = openssl_error_string()) !== false) { echo $e . "\n"; print "

    "; } return false; } $ca="file://".$enrollment['ca_crt']; $this->crt = openssl_csr_sign($this->csr, $ca, $enrollment['ca_key'], 3650, $config); if ($this->crt==FALSE) { while (($e = openssl_error_string()) !== false) { echo $e . "\n"; print "

    "; } return false; } openssl_csr_export ($this->csr, $this->csr_out); openssl_pkey_export ($this->key, $this->key_out, $this->password, $config); openssl_x509_export ($this->crt, $this->crt_out); openssl_pkcs12_export ($this->crt, $this->p12_out, $this->key, $this->password); $ret=array( 'csr' => $this->csr_out, 'crt' => $this->crt_out, 'key' => $this->key_out, 'pkey'=> $public_key, 'p12' => $this->p12_out, 'ca' => file_get_contents($enrollment['ca_crt']) ); return $ret; } function exportCertificateX509() { if (!$this->owner) return; Header("Content-type: application/x-crt"); $header=sprintf("Content-Disposition: inline; filename=sipthor-owner-certificate-%s.crt",$this->owner); Header($header); $cert=$this->generateCertificate(); $crt=$cert['crt'].$cert['key']; print $crt; } function exportCertificateP12() { if (!$this->owner) return; $cert=$this->generateCertificate(); Header("Content-type: application/x-p12"); $header=sprintf("Content-Disposition: inline; filename=sipthor-owner-certificate-%s.p12",$this->owner); Header($header); print $cert['p12']; } function isEmbedded() { // return true if page was loaded from non-session based web session if ($_SERVER['SSL_CLIENT_CERT'] || $_SERVER['PHP_AUTH_DIGEST']) { return true; } return false; } function changeLanguage($lang='en',$domain='cdrtool') { // run dpkg-reconfigure locales and select support languages .utf8 $lang = $this->languageCodeFor(isset($lang) ? $lang : 'en'); $lang.='.utf8'; setlocale(LC_ALL, $lang); bindtextdomain($domain, '/var/www/CDRTool/po/locale'); bind_textdomain_codeset($domain,'UTF-8'); textdomain($domain); } // return full language code for given 2 letter language code function languageCodeFor($lang='en') { $lang = isset($lang) ? strtolower($lang) : 'en'; switch ($lang) { case 'en': return 'en_US'; // this can be C or en_US case 'ja': return 'ja_JP'; default : return ($lang . '_' . strtoupper($lang)); } return 'C'; // this will never be reached } function showDirectorySearchForm () { if (in_array("trunking",$this->groups)) { return false; } print "
    url method=post> "; print $this->hiddenElements; print "
    "; print " ",$_REQUEST['firstname']); print "
    "; print "",$_REQUEST['lastname']); print ""; print "
    "; } function showSearchDirectory() { if (!$this->show_directory) { return false; } $this->maxrowsperpage=20; $this->showDirectorySearchForm(); if ($_REQUEST['firstname'] || $_REQUEST['lastname']) { if ($_REQUEST['firstname'] && strlen($_REQUEST['firstname']) < 3) { return false; } if ($_REQUEST['lastname'] && strlen($_REQUEST['lastname']) < 3) { return false; } } else { return false; } $this->next = $_REQUEST['next']; // Filter $filter=array('firstName'=> trim($_REQUEST['firstname']), 'lastName' => trim($_REQUEST['lastname']) ); // Range $range=array('start' => intval($this->next), 'count' => intval($this->maxrowsperpage) ); // Order if (!$this->sorting['sortBy']) $this->sorting['sortBy'] = 'changeDate'; if (!$this->sorting['sortOrder']) $this->sorting['sortOrder'] = 'DESC'; $orderBy = array('attribute' => $this->sorting['sortBy'], 'direction' => $this->sorting['sortOrder'] ); // Compose query $Query=array('filter' => $filter, 'orderBy' => $orderBy, 'range' => $range ); // Insert credetials $this->SipPort->addHeader($this->SoapAuthAdmin); // Call function $result = $this->SipPort->getAccounts($Query); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

    Error from %s: %s (%s): %s",$this->SoapEngine->SOAPurl,$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } $this->rows = $result->total; if (!$this->next) $this->next=0; if ($this->rows > $this->maxrowsperpage) { $maxrows = $this->maxrowsperpage + $this->next; if ($maxrows > $this->rows) $maxrows = $this->maxrowsperpage; } else { $maxrows=$this->rows; } if ($this->rows) { print "

    "; printf(_("%s contacts found. "),$this->rows); if ($this->isEmbedded()) { //printf (_("Click on %s to add a Contact to Blink. "),$this->plus_sign_img); } print "
    "; print ""; print ""; print ""; print ""; print " "; $i=0; while ($i < $maxrows) { if (!$result->accounts[$i]) break; $account = $result->accounts[$i]; $index=$this->next+$i+1; $rr=floor($index/2); $mod=$index-$rr*2; if ($mod ==0) { $_class='odd'; } else { $_class='even'; } $i++; $name=$account->firstName.' '.$account->lastName; $sip_account=sprintf("%s@%s",$account->id->username,$account->id->domain); $contacts_url=sprintf("%s",$this->url,$sip_account,urlencode($name),$sip_account,$this->phonebook_img); if ($this->isEmbedded()) { //$add_contact_url=sprintf("%s",$sip_account,$name,$this->plus_sign_img); printf ("", $_class, $index, $name, $sip_account, $account->timezone, $this->PhoneDialURL($sip_account), $add_contact_url ); } else { printf ("", $_class, $index, $name, $sip_account, $account->timezone, $this->PhoneDialURL($sip_account), $contacts_url ); } } print "
    "; print _('Display Name'); print ""; print _('SIP Address'); print ""; print _('Timezone'); print ""; print _('Action'); print "
    %d%s%s%s%s %s
    %d%s%s%s%s %s
    "; $this->showPagination($maxrows); return true; } } function showPagination($maxrows) { $url = sprintf("%s&tab=%s&firstname=%s&lastname%s", $this->url, $this->tab, urlencode($_REQUEST['firstname']), urlencode($_REQUEST['lastname']) ); print "

    "; if ($this->next != 0 ) { $show_next=$this->maxrowsperpage-$this->next; if ($show_next < 0) { $mod_show_next = $show_next-2*$show_next; } if (!$mod_show_next) $mod_show_next=0; if ($mod_show_next/$this->maxrowsperpage >= 1) { printf ("Begin ",$url); } printf ("Previous ",$url,$mod_show_next); } print " "; if ($this->next + $this->maxrowsperpage < $this->rows) { $show_next = $this->maxrowsperpage + $this->next; printf ("Next ",$url,$show_next); } print "
    "; } } function lookupGeoLocation($ip) { if ($_loc=geoip_record_by_name($ip)) { $_loc['timezone'] = get_time_zone($_loc['country_code'], $_loc['region']); $_loc['region'] = get_region($_loc['country_code'], $_loc['region']); $country_transition = array( "A1" => "N/A", "A2" => "N/A", "O1" => "N/A", "AP" => "N/A", "GB" => "UK"); if (array_key_exists($_loc['country_code'],$country_transition)) { $_loc['country_code'] = $country_transition[$_loc['country_code']]; } return $_loc; } else { return array(); } } function get_region($country, $region) { if ($country == "US" || $country =="CA" ) { $full_region = $region; // If region can't be found make it a default region to prevent NGNpro error if ($full_region == '' && $country == "US") { $full_region = "NY"; } else if ($full_region == '' && $country == "CA") { $full_region = "QC"; } } else { $full_region=''; } return $full_region; } function get_time_zone($country, $region) { switch ($country) { case "US": switch ($region) { case "AL": $timezone = "America/Chicago"; break; case "AK": $timezone = "America/Anchorage"; break; case "AZ": $timezone = "America/Phoenix"; break; case "AR": $timezone = "America/Chicago"; break; case "CA": $timezone = "America/Los_Angeles"; break; case "CO": $timezone = "America/Denver"; break; case "CT": $timezone = "America/New_York"; break; case "DE": $timezone = "America/New_York"; break; case "DC": $timezone = "America/New_York"; break; case "FL": $timezone = "America/New_York"; break; case "GA": $timezone = "America/New_York"; break; case "HI": $timezone = "Pacific/Honolulu"; break; case "ID": $timezone = "America/Denver"; break; case "IL": $timezone = "America/Chicago"; break; case "IN": $timezone = "America/Indianapolis"; break; case "IA": $timezone = "America/Chicago"; break; case "KS": $timezone = "America/Chicago"; break; case "KY": $timezone = "America/New_York"; break; case "LA": $timezone = "America/Chicago"; break; case "ME": $timezone = "America/New_York"; break; case "MD": $timezone = "America/New_York"; break; case "MA": $timezone = "America/New_York"; break; case "MI": $timezone = "America/New_York"; break; case "MN": $timezone = "America/Chicago"; break; case "MS": $timezone = "America/Chicago"; break; case "MO": $timezone = "America/Chicago"; break; case "MT": $timezone = "America/Denver"; break; case "NE": $timezone = "America/Chicago"; break; case "NV": $timezone = "America/Los_Angeles"; break; case "NH": $timezone = "America/New_York"; break; case "NJ": $timezone = "America/New_York"; break; case "NM": $timezone = "America/Denver"; break; case "NY": $timezone = "America/New_York"; break; case "NC": $timezone = "America/New_York"; break; case "ND": $timezone = "America/Chicago"; break; case "OH": $timezone = "America/New_York"; break; case "OK": $timezone = "America/Chicago"; break; case "OR": $timezone = "America/Los_Angeles"; break; case "PA": $timezone = "America/New_York"; break; case "RI": $timezone = "America/New_York"; break; case "SC": $timezone = "America/New_York"; break; case "SD": $timezone = "America/Chicago"; break; case "TN": $timezone = "America/Chicago"; break; case "TX": $timezone = "America/Chicago"; break; case "UT": $timezone = "America/Denver"; break; case "VT": $timezone = "America/New_York"; break; case "VA": $timezone = "America/New_York"; break; case "WA": $timezone = "America/Los_Angeles"; break; case "WV": $timezone = "America/New_York"; break; case "WI": $timezone = "America/Chicago"; break; case "WY": $timezone = "America/Denver"; break; } break; case "CA": switch ($region) { case "AB": $timezone = "America/Edmonton"; break; case "BC": $timezone = "America/Vancouver"; break; case "MB": $timezone = "America/Winnipeg"; break; case "NB": $timezone = "America/Halifax"; break; case "NL": $timezone = "America/St_Johns"; break; case "NT": $timezone = "America/Yellowknife"; break; case "NS": $timezone = "America/Halifax"; break; case "NU": $timezone = "America/Rankin_Inlet"; break; case "ON": $timezone = "America/Rainy_River"; break; case "PE": $timezone = "America/Halifax"; break; case "QC": $timezone = "America/Montreal"; break; case "SK": $timezone = "America/Regina"; break; case "YT": $timezone = "America/Whitehorse"; break; } break; case "AU": switch ($region) { case "01": $timezone = "Australia/Canberra"; break; case "02": $timezone = "Australia/NSW"; break; case "03": $timezone = "Australia/North"; break; case "04": $timezone = "Australia/Queensland"; break; case "05": $timezone = "Australia/South"; break; case "06": $timezone = "Australia/Tasmania"; break; case "07": $timezone = "Australia/Victoria"; break; case "08": $timezone = "Australia/West"; break; } break; case "AS": $timezone = "US/Samoa"; break; case "CI": $timezone = "Africa/Abidjan"; break; case "GH": $timezone = "Africa/Accra"; break; case "DZ": $timezone = "Africa/Algiers"; break; case "ER": $timezone = "Africa/Asmera"; break; case "ML": $timezone = "Africa/Bamako"; break; case "CF": $timezone = "Africa/Bangui"; break; case "GM": $timezone = "Africa/Banjul"; break; case "GW": $timezone = "Africa/Bissau"; break; case "CG": $timezone = "Africa/Brazzaville"; break; case "BI": $timezone = "Africa/Bujumbura"; break; case "EG": $timezone = "Africa/Cairo"; break; case "MA": $timezone = "Africa/Casablanca"; break; case "GN": $timezone = "Africa/Conakry"; break; case "SN": $timezone = "Africa/Dakar"; break; case "DJ": $timezone = "Africa/Djibouti"; break; case "SL": $timezone = "Africa/Freetown"; break; case "BW": $timezone = "Africa/Gaborone"; break; case "ZW": $timezone = "Africa/Harare"; break; case "ZA": $timezone = "Africa/Johannesburg"; break; case "UG": $timezone = "Africa/Kampala"; break; case "SD": $timezone = "Africa/Khartoum"; break; case "RW": $timezone = "Africa/Kigali"; break; case "NG": $timezone = "Africa/Lagos"; break; case "GA": $timezone = "Africa/Libreville"; break; case "TG": $timezone = "Africa/Lome"; break; case "AO": $timezone = "Africa/Luanda"; break; case "ZM": $timezone = "Africa/Lusaka"; break; case "GQ": $timezone = "Africa/Malabo"; break; case "MZ": $timezone = "Africa/Maputo"; break; case "LS": $timezone = "Africa/Maseru"; break; case "SZ": $timezone = "Africa/Mbabane"; break; case "SO": $timezone = "Africa/Mogadishu"; break; case "LR": $timezone = "Africa/Monrovia"; break; case "KE": $timezone = "Africa/Nairobi"; break; case "TD": $timezone = "Africa/Ndjamena"; break; case "NE": $timezone = "Africa/Niamey"; break; case "MR": $timezone = "Africa/Nouakchott"; break; case "BF": $timezone = "Africa/Ouagadougou"; break; case "ST": $timezone = "Africa/Sao_Tome"; break; case "LY": $timezone = "Africa/Tripoli"; break; case "TN": $timezone = "Africa/Tunis"; break; case "AI": $timezone = "America/Anguilla"; break; case "AG": $timezone = "America/Antigua"; break; case "AW": $timezone = "America/Aruba"; break; case "BB": $timezone = "America/Barbados"; break; case "BZ": $timezone = "America/Belize"; break; case "CO": $timezone = "America/Bogota"; break; case "VE": $timezone = "America/Caracas"; break; case "KY": $timezone = "America/Cayman"; break; case "CR": $timezone = "America/Costa_Rica"; break; case "DM": $timezone = "America/Dominica"; break; case "SV": $timezone = "America/El_Salvador"; break; case "GD": $timezone = "America/Grenada"; break; case "FR": $timezone = "Europe/Paris"; break; case "GP": $timezone = "America/Guadeloupe"; break; case "GT": $timezone = "America/Guatemala"; break; case "GY": $timezone = "America/Guyana"; break; case "CU": $timezone = "America/Havana"; break; case "JM": $timezone = "America/Jamaica"; break; case "BO": $timezone = "America/La_Paz"; break; case "PE": $timezone = "America/Lima"; break; case "NI": $timezone = "America/Managua"; break; case "MQ": $timezone = "America/Martinique"; break; case "UY": $timezone = "America/Montevideo"; break; case "MS": $timezone = "America/Montserrat"; break; case "BS": $timezone = "America/Nassau"; break; case "PA": $timezone = "America/Panama"; break; case "SR": $timezone = "America/Paramaribo"; break; case "PR": $timezone = "America/Puerto_Rico"; break; case "KN": $timezone = "America/St_Kitts"; break; case "LC": $timezone = "America/St_Lucia"; break; case "VC": $timezone = "America/St_Vincent"; break; case "HN": $timezone = "America/Tegucigalpa"; break; case "YE": $timezone = "Asia/Aden"; break; case "JO": $timezone = "Asia/Amman"; break; case "TM": $timezone = "Asia/Ashgabat"; break; case "IQ": $timezone = "Asia/Baghdad"; break; case "BH": $timezone = "Asia/Bahrain"; break; case "AZ": $timezone = "Asia/Baku"; break; case "TH": $timezone = "Asia/Bangkok"; break; case "LB": $timezone = "Asia/Beirut"; break; case "KG": $timezone = "Asia/Bishkek"; break; case "BN": $timezone = "Asia/Brunei"; break; case "IN": $timezone = "Asia/Calcutta"; break; case "MN": $timezone = "Asia/Choibalsan"; break; case "LK": $timezone = "Asia/Colombo"; break; case "BD": $timezone = "Asia/Dhaka"; break; case "AE": $timezone = "Asia/Dubai"; break; case "TJ": $timezone = "Asia/Dushanbe"; break; case "HK": $timezone = "Asia/Hong_Kong"; break; case "TR": $timezone = "Asia/Istanbul"; break; case "IL": $timezone = "Asia/Jerusalem"; break; case "AF": $timezone = "Asia/Kabul"; break; case "PK": $timezone = "Asia/Karachi"; break; case "NP": $timezone = "Asia/Katmandu"; break; case "KW": $timezone = "Asia/Kuwait"; break; case "MO": $timezone = "Asia/Macao"; break; case "PH": $timezone = "Asia/Manila"; break; case "OM": $timezone = "Asia/Muscat"; break; case "CY": $timezone = "Asia/Nicosia"; break; case "KP": $timezone = "Asia/Pyongyang"; break; case "QA": $timezone = "Asia/Qatar"; break; case "MM": $timezone = "Asia/Rangoon"; break; case "SA": $timezone = "Asia/Riyadh"; break; case "KR": $timezone = "Asia/Seoul"; break; case "SG": $timezone = "Asia/Singapore"; break; case "TW": $timezone = "Asia/Taipei"; break; case "GE": $timezone = "Asia/Tbilisi"; break; case "BT": $timezone = "Asia/Thimphu"; break; case "JP": $timezone = "Asia/Tokyo"; break; case "LA": $timezone = "Asia/Vientiane"; break; case "AM": $timezone = "Asia/Yerevan"; break; case "BM": $timezone = "Atlantic/Bermuda"; break; case "CV": $timezone = "Atlantic/Cape_Verde"; break; case "FO": $timezone = "Atlantic/Faeroe"; break; case "IS": $timezone = "Atlantic/Reykjavik"; break; case "GS": $timezone = "Atlantic/South_Georgia"; break; case "SH": $timezone = "Atlantic/St_Helena"; break; case "CL": $timezone = "Chile/Continental"; break; case "NL": $timezone = "Europe/Amsterdam"; break; case "AD": $timezone = "Europe/Andorra"; break; case "GR": $timezone = "Europe/Athens"; break; case "YU": $timezone = "Europe/Belgrade"; break; case "DE": $timezone = "Europe/Berlin"; break; case "SK": $timezone = "Europe/Bratislava"; break; case "BE": $timezone = "Europe/Brussels"; break; case "RO": $timezone = "Europe/Bucharest"; break; case "HU": $timezone = "Europe/Budapest"; break; case "DK": $timezone = "Europe/Copenhagen"; break; case "IE": $timezone = "Europe/Dublin"; break; case "GI": $timezone = "Europe/Gibraltar"; break; case "FI": $timezone = "Europe/Helsinki"; break; case "SI": $timezone = "Europe/Ljubljana"; break; case "GB": $timezone = "Europe/London"; break; case "LU": $timezone = "Europe/Luxembourg"; break; case "MT": $timezone = "Europe/Malta"; break; case "BY": $timezone = "Europe/Minsk"; break; case "MC": $timezone = "Europe/Monaco"; break; case "NO": $timezone = "Europe/Oslo"; break; case "CZ": $timezone = "Europe/Prague"; break; case "LV": $timezone = "Europe/Riga"; break; case "IT": $timezone = "Europe/Rome"; break; case "SM": $timezone = "Europe/San_Marino"; break; case "BA": $timezone = "Europe/Sarajevo"; break; case "MK": $timezone = "Europe/Skopje"; break; case "BG": $timezone = "Europe/Sofia"; break; case "SE": $timezone = "Europe/Stockholm"; break; case "EE": $timezone = "Europe/Tallinn"; break; case "AL": $timezone = "Europe/Tirane"; break; case "LI": $timezone = "Europe/Vaduz"; break; case "VA": $timezone = "Europe/Vatican"; break; case "AT": $timezone = "Europe/Vienna"; break; case "LT": $timezone = "Europe/Vilnius"; break; case "PL": $timezone = "Europe/Warsaw"; break; case "HR": $timezone = "Europe/Zagreb"; break; case "IR": $timezone = "Asia/Tehran"; break; case "MG": $timezone = "Indian/Antananarivo"; break; case "CX": $timezone = "Indian/Christmas"; break; case "CC": $timezone = "Indian/Cocos"; break; case "KM": $timezone = "Indian/Comoro"; break; case "MV": $timezone = "Indian/Maldives"; break; case "MU": $timezone = "Indian/Mauritius"; break; case "YT": $timezone = "Indian/Mayotte"; break; case "RE": $timezone = "Indian/Reunion"; break; case "FJ": $timezone = "Pacific/Fiji"; break; case "TV": $timezone = "Pacific/Funafuti"; break; case "GU": $timezone = "Pacific/Guam"; break; case "NR": $timezone = "Pacific/Nauru"; break; case "NU": $timezone = "Pacific/Niue"; break; case "NF": $timezone = "Pacific/Norfolk"; break; case "PW": $timezone = "Pacific/Palau"; break; case "PN": $timezone = "Pacific/Pitcairn"; break; case "CK": $timezone = "Pacific/Rarotonga"; break; case "WS": $timezone = "Pacific/Samoa"; break; case "KI": $timezone = "Pacific/Tarawa"; break; case "TO": $timezone = "Pacific/Tongatapu"; break; case "WF": $timezone = "Pacific/Wallis"; break; case "TZ": $timezone = "Africa/Dar_es_Salaam"; break; case "VN": $timezone = "Asia/Phnom_Penh"; break; case "KH": $timezone = "Asia/Phnom_Penh"; break; case "CM": $timezone = "Africa/Lagos"; break; case "DO": $timezone = "America/Santo_Domingo"; break; case "ET": $timezone = "Africa/Addis_Ababa"; break; case "FX": $timezone = "Europe/Paris"; break; case "HT": $timezone = "America/Port-au-Prince"; break; case "CH": $timezone = "Europe/Zurich"; break; case "AN": $timezone = "America/Curacao"; break; case "BJ": $timezone = "Africa/Porto-Novo"; break; case "EH": $timezone = "Africa/El_Aaiun"; break; case "FK": $timezone = "Atlantic/Stanley"; break; case "GF": $timezone = "America/Cayenne"; break; case "IO": $timezone = "Indian/Chagos"; break; case "MD": $timezone = "Europe/Chisinau"; break; case "MP": $timezone = "Pacific/Saipan"; break; case "MW": $timezone = "Africa/Blantyre"; break; case "NA": $timezone = "Africa/Windhoek"; break; case "NC": $timezone = "Pacific/Noumea"; break; case "PG": $timezone = "Pacific/Port_Moresby"; break; case "PM": $timezone = "America/Miquelon"; break; case "PS": $timezone = "Asia/Gaza"; break; case "PY": $timezone = "America/Asuncion"; break; case "SB": $timezone = "Pacific/Guadalcanal"; break; case "SC": $timezone = "Indian/Mahe"; break; case "SJ": $timezone = "Arctic/Longyearbyen"; break; case "SY": $timezone = "Asia/Damascus"; break; case "TC": $timezone = "America/Grand_Turk"; break; case "TF": $timezone = "Indian/Kerguelen"; break; case "TK": $timezone = "Pacific/Fakaofo"; break; case "TT": $timezone = "America/Port_of_Spain"; break; case "VG": $timezone = "America/Tortola"; break; case "VI": $timezone = "America/St_Thomas"; break; case "VU": $timezone = "Pacific/Efate"; break; case "RS": $timezone = "Europe/Belgrade"; break; case "ME": $timezone = "Europe/Podgorica"; break; case "AX": $timezone = "Europe/Mariehamn"; break; case "GG": $timezone = "Europe/Guernsey"; break; case "IM": $timezone = "Europe/Isle_of_Man"; break; case "JE": $timezone = "Europe/Jersey"; break; case "BL": $timezone = "America/St_Barthelemy"; break; case "MF": $timezone = "America/Marigot"; break; case "AR": switch ($region) { case "01": $timezone = "America/Argentina/Buenos_Aires"; break; case "02": $timezone = "America/Argentina/Catamarca"; break; case "03": $timezone = "America/Argentina/Tucuman"; break; case "04": $timezone = "America/Argentina/Rio_Gallegos"; break; case "05": $timezone = "America/Argentina/Cordoba"; break; case "06": $timezone = "America/Argentina/Tucuman"; break; case "07": $timezone = "America/Argentina/Buenos_Aires"; break; case "08": $timezone = "America/Argentina/Buenos_Aires"; break; case "09": $timezone = "America/Argentina/Tucuman"; break; case "10": $timezone = "America/Argentina/Jujuy"; break; case "11": $timezone = "America/Argentina/San_Luis"; break; case "12": $timezone = "America/Argentina/La_Rioja"; break; case "13": $timezone = "America/Argentina/Mendoza"; break; case "14": $timezone = "America/Argentina/Buenos_Aires"; break; case "15": $timezone = "America/Argentina/San_Luis"; break; case "16": $timezone = "America/Argentina/Buenos_Aires"; break; case "17": $timezone = "America/Argentina/Salta"; break; case "18": $timezone = "America/Argentina/San_Juan"; break; case "19": $timezone = "America/Argentina/San_Luis"; break; case "20": $timezone = "America/Argentina/Rio_Gallegos"; break; case "21": $timezone = "America/Argentina/Buenos_Aires"; break; case "22": $timezone = "America/Argentina/Catamarca"; break; case "23": $timezone = "America/Argentina/Ushuaia"; break; case "24": $timezone = "America/Argentina/Tucuman"; break; } break; case "BR": switch ($region) { case "01": $timezone = "America/Rio_Branco"; break; case "02": $timezone = "America/Maceio"; break; case "03": $timezone = "America/Sao_Paulo"; break; case "04": $timezone = "America/Manaus"; break; case "05": $timezone = "America/Bahia"; break; case "06": $timezone = "America/Fortaleza"; break; case "07": $timezone = "America/Sao_Paulo"; break; case "08": $timezone = "America/Sao_Paulo"; break; case "11": $timezone = "America/Campo_Grande"; break; case "13": $timezone = "America/Belem"; break; case "14": $timezone = "America/Cuiaba"; break; case "15": $timezone = "America/Sao_Paulo"; break; case "16": $timezone = "America/Belem"; break; case "17": $timezone = "America/Recife"; break; case "18": $timezone = "America/Sao_Paulo"; break; case "20": $timezone = "America/Fortaleza"; break; case "21": $timezone = "America/Sao_Paulo"; break; case "22": $timezone = "America/Recife"; break; case "23": $timezone = "America/Sao_Paulo"; break; case "24": $timezone = "America/Porto_Velho"; break; case "25": $timezone = "America/Boa_Vista"; break; case "26": $timezone = "America/Sao_Paulo"; break; case "27": $timezone = "America/Sao_Paulo"; break; case "28": $timezone = "America/Maceio"; break; case "29": $timezone = "America/Sao_Paulo"; break; case "30": $timezone = "America/Recife"; break; case "31": $timezone = "America/Araguaina"; break; } break; case "CD": switch ($region) { case "02": $timezone = "Africa/Kinshasa"; break; case "05": $timezone = "Africa/Lubumbashi"; break; case "06": $timezone = "Africa/Kinshasa"; break; case "08": $timezone = "Africa/Kinshasa"; break; case "10": $timezone = "Africa/Lubumbashi"; break; case "11": $timezone = "Africa/Lubumbashi"; break; case "12": $timezone = "Africa/Lubumbashi"; break; } break; case "CN": switch ($region) { case "01": $timezone = "Asia/Shanghai"; break; case "02": $timezone = "Asia/Shanghai"; break; case "03": $timezone = "Asia/Shanghai"; break; case "04": $timezone = "Asia/Shanghai"; break; case "05": $timezone = "Asia/Harbin"; break; case "06": $timezone = "Asia/Chongqing"; break; case "07": $timezone = "Asia/Shanghai"; break; case "08": $timezone = "Asia/Harbin"; break; case "09": $timezone = "Asia/Shanghai"; break; case "10": $timezone = "Asia/Shanghai"; break; case "11": $timezone = "Asia/Chongqing"; break; case "12": $timezone = "Asia/Shanghai"; break; case "13": $timezone = "Asia/Urumqi"; break; case "14": $timezone = "Asia/Chongqing"; break; case "15": $timezone = "Asia/Chongqing"; break; case "16": $timezone = "Asia/Chongqing"; break; case "18": $timezone = "Asia/Chongqing"; break; case "19": $timezone = "Asia/Harbin"; break; case "20": $timezone = "Asia/Harbin"; break; case "21": $timezone = "Asia/Chongqing"; break; case "22": $timezone = "Asia/Harbin"; break; case "23": $timezone = "Asia/Shanghai"; break; case "24": $timezone = "Asia/Chongqing"; break; case "25": $timezone = "Asia/Shanghai"; break; case "26": $timezone = "Asia/Chongqing"; break; case "28": $timezone = "Asia/Shanghai"; break; case "29": $timezone = "Asia/Chongqing"; break; case "30": $timezone = "Asia/Chongqing"; break; case "31": $timezone = "Asia/Chongqing"; break; case "32": $timezone = "Asia/Chongqing"; break; case "33": $timezone = "Asia/Chongqing"; break; } break; case "EC": switch ($region) { case "01": $timezone = "Pacific/Galapagos"; break; case "02": $timezone = "America/Guayaquil"; break; case "03": $timezone = "America/Guayaquil"; break; case "04": $timezone = "America/Guayaquil"; break; case "05": $timezone = "America/Guayaquil"; break; case "06": $timezone = "America/Guayaquil"; break; case "07": $timezone = "America/Guayaquil"; break; case "08": $timezone = "America/Guayaquil"; break; case "09": $timezone = "America/Guayaquil"; break; case "10": $timezone = "America/Guayaquil"; break; case "11": $timezone = "America/Guayaquil"; break; case "12": $timezone = "America/Guayaquil"; break; case "13": $timezone = "America/Guayaquil"; break; case "14": $timezone = "America/Guayaquil"; break; case "15": $timezone = "America/Guayaquil"; break; case "17": $timezone = "America/Guayaquil"; break; case "18": $timezone = "America/Guayaquil"; break; case "19": $timezone = "America/Guayaquil"; break; case "20": $timezone = "America/Guayaquil"; break; case "22": $timezone = "America/Guayaquil"; break; } break; case "ES": switch ($region) { case "07": $timezone = "Europe/Madrid"; break; case "27": $timezone = "Europe/Madrid"; break; case "29": $timezone = "Europe/Madrid"; break; case "31": $timezone = "Europe/Madrid"; break; case "32": $timezone = "Europe/Madrid"; break; case "34": $timezone = "Europe/Madrid"; break; case "39": $timezone = "Europe/Madrid"; break; case "51": $timezone = "Africa/Ceuta"; break; case "52": $timezone = "Europe/Madrid"; break; case "53": $timezone = "Atlantic/Canary"; break; case "54": $timezone = "Europe/Madrid"; break; case "55": $timezone = "Europe/Madrid"; break; case "56": $timezone = "Europe/Madrid"; break; case "57": $timezone = "Europe/Madrid"; break; case "58": $timezone = "Europe/Madrid"; break; case "59": $timezone = "Europe/Madrid"; break; case "60": $timezone = "Europe/Madrid"; break; } break; case "GL": switch ($region) { case "01": $timezone = "America/Thule"; break; case "02": $timezone = "America/Godthab"; break; case "03": $timezone = "America/Godthab"; break; } break; case "ID": switch ($region) { case "01": $timezone = "Asia/Pontianak"; break; case "02": $timezone = "Asia/Makassar"; break; case "03": $timezone = "Asia/Jakarta"; break; case "04": $timezone = "Asia/Jakarta"; break; case "05": $timezone = "Asia/Jakarta"; break; case "06": $timezone = "Asia/Jakarta"; break; case "07": $timezone = "Asia/Jakarta"; break; case "08": $timezone = "Asia/Jakarta"; break; case "09": $timezone = "Asia/Jayapura"; break; case "10": $timezone = "Asia/Jakarta"; break; case "11": $timezone = "Asia/Pontianak"; break; case "12": $timezone = "Asia/Makassar"; break; case "13": $timezone = "Asia/Makassar"; break; case "14": $timezone = "Asia/Makassar"; break; case "15": $timezone = "Asia/Jakarta"; break; case "16": $timezone = "Asia/Makassar"; break; case "17": $timezone = "Asia/Makassar"; break; case "18": $timezone = "Asia/Makassar"; break; case "19": $timezone = "Asia/Pontianak"; break; case "20": $timezone = "Asia/Makassar"; break; case "21": $timezone = "Asia/Makassar"; break; case "22": $timezone = "Asia/Makassar"; break; case "23": $timezone = "Asia/Makassar"; break; case "24": $timezone = "Asia/Jakarta"; break; case "25": $timezone = "Asia/Pontianak"; break; case "26": $timezone = "Asia/Pontianak"; break; case "30": $timezone = "Asia/Jakarta"; break; case "31": $timezone = "Asia/Makassar"; break; case "33": $timezone = "Asia/Jakarta"; break; } break; case "KZ": switch ($region) { case "01": $timezone = "Asia/Almaty"; break; case "02": $timezone = "Asia/Almaty"; break; case "03": $timezone = "Asia/Qyzylorda"; break; case "04": $timezone = "Asia/Aqtobe"; break; case "05": $timezone = "Asia/Qyzylorda"; break; case "06": $timezone = "Asia/Aqtau"; break; case "07": $timezone = "Asia/Oral"; break; case "08": $timezone = "Asia/Qyzylorda"; break; case "09": $timezone = "Asia/Aqtau"; break; case "10": $timezone = "Asia/Qyzylorda"; break; case "11": $timezone = "Asia/Almaty"; break; case "12": $timezone = "Asia/Qyzylorda"; break; case "13": $timezone = "Asia/Aqtobe"; break; case "14": $timezone = "Asia/Qyzylorda"; break; case "15": $timezone = "Asia/Almaty"; break; case "16": $timezone = "Asia/Aqtobe"; break; case "17": $timezone = "Asia/Almaty"; break; } break; case "MX": switch ($region) { case "01": $timezone = "America/Mexico_City"; break; case "02": $timezone = "America/Tijuana"; break; case "03": $timezone = "America/Hermosillo"; break; case "04": $timezone = "America/Merida"; break; case "05": $timezone = "America/Mexico_City"; break; case "06": $timezone = "America/Chihuahua"; break; case "07": $timezone = "America/Monterrey"; break; case "08": $timezone = "America/Mexico_City"; break; case "09": $timezone = "America/Mexico_City"; break; case "10": $timezone = "America/Mazatlan"; break; case "11": $timezone = "America/Mexico_City"; break; case "12": $timezone = "America/Mexico_City"; break; case "13": $timezone = "America/Mexico_City"; break; case "14": $timezone = "America/Mazatlan"; break; case "15": $timezone = "America/Chihuahua"; break; case "16": $timezone = "America/Mexico_City"; break; case "17": $timezone = "America/Mexico_City"; break; case "18": $timezone = "America/Mazatlan"; break; case "19": $timezone = "America/Monterrey"; break; case "20": $timezone = "America/Mexico_City"; break; case "21": $timezone = "America/Mexico_City"; break; case "22": $timezone = "America/Mexico_City"; break; case "23": $timezone = "America/Cancun"; break; case "24": $timezone = "America/Mexico_City"; break; case "25": $timezone = "America/Mazatlan"; break; case "26": $timezone = "America/Hermosillo"; break; case "27": $timezone = "America/Merida"; break; case "28": $timezone = "America/Monterrey"; break; case "29": $timezone = "America/Mexico_City"; break; case "30": $timezone = "America/Mexico_City"; break; case "31": $timezone = "America/Merida"; break; case "32": $timezone = "America/Monterrey"; break; } break; case "MY": switch ($region) { case "01": $timezone = "Asia/Kuala_Lumpur"; break; case "02": $timezone = "Asia/Kuala_Lumpur"; break; case "03": $timezone = "Asia/Kuala_Lumpur"; break; case "04": $timezone = "Asia/Kuala_Lumpur"; break; case "05": $timezone = "Asia/Kuala_Lumpur"; break; case "06": $timezone = "Asia/Kuala_Lumpur"; break; case "07": $timezone = "Asia/Kuala_Lumpur"; break; case "08": $timezone = "Asia/Kuala_Lumpur"; break; case "09": $timezone = "Asia/Kuala_Lumpur"; break; case "11": $timezone = "Asia/Kuching"; break; case "12": $timezone = "Asia/Kuala_Lumpur"; break; case "13": $timezone = "Asia/Kuala_Lumpur"; break; case "14": $timezone = "Asia/Kuala_Lumpur"; break; case "15": $timezone = "Asia/Kuching"; break; case "16": $timezone = "Asia/Kuching"; break; } break; case "NZ": switch ($region) { case "85": $timezone = "Pacific/Auckland"; break; case "E7": $timezone = "Pacific/Auckland"; break; case "E8": $timezone = "Pacific/Auckland"; break; case "E9": $timezone = "Pacific/Auckland"; break; case "F1": $timezone = "Pacific/Auckland"; break; case "F2": $timezone = "Pacific/Auckland"; break; case "F3": $timezone = "Pacific/Auckland"; break; case "F4": $timezone = "Pacific/Auckland"; break; case "F5": $timezone = "Pacific/Auckland"; break; case "F7": $timezone = "Pacific/Chatham"; break; case "F8": $timezone = "Pacific/Auckland"; break; case "F9": $timezone = "Pacific/Auckland"; break; case "G1": $timezone = "Pacific/Auckland"; break; case "G2": $timezone = "Pacific/Auckland"; break; case "G3": $timezone = "Pacific/Auckland"; break; } break; case "PT": switch ($region) { case "02": $timezone = "Europe/Lisbon"; break; case "03": $timezone = "Europe/Lisbon"; break; case "04": $timezone = "Europe/Lisbon"; break; case "05": $timezone = "Europe/Lisbon"; break; case "06": $timezone = "Europe/Lisbon"; break; case "07": $timezone = "Europe/Lisbon"; break; case "08": $timezone = "Europe/Lisbon"; break; case "09": $timezone = "Europe/Lisbon"; break; case "10": $timezone = "Atlantic/Madeira"; break; case "11": $timezone = "Europe/Lisbon"; break; case "13": $timezone = "Europe/Lisbon"; break; case "14": $timezone = "Europe/Lisbon"; break; case "16": $timezone = "Europe/Lisbon"; break; case "17": $timezone = "Europe/Lisbon"; break; case "18": $timezone = "Europe/Lisbon"; break; case "19": $timezone = "Europe/Lisbon"; break; case "20": $timezone = "Europe/Lisbon"; break; case "21": $timezone = "Europe/Lisbon"; break; case "22": $timezone = "Europe/Lisbon"; break; } break; case "RU": switch ($region) { case "01": $timezone = "Europe/Volgograd"; break; case "02": $timezone = "Asia/Irkutsk"; break; case "03": $timezone = "Asia/Novokuznetsk"; break; case "04": $timezone = "Asia/Novosibirsk"; break; case "05": $timezone = "Asia/Vladivostok"; break; case "06": $timezone = "Europe/Moscow"; break; case "07": $timezone = "Europe/Volgograd"; break; case "08": $timezone = "Europe/Samara"; break; case "09": $timezone = "Europe/Moscow"; break; case "10": $timezone = "Europe/Moscow"; break; case "11": $timezone = "Asia/Irkutsk"; break; case "13": $timezone = "Asia/Yekaterinburg"; break; case "14": $timezone = "Asia/Irkutsk"; break; case "15": $timezone = "Asia/Anadyr"; break; case "16": $timezone = "Europe/Samara"; break; case "17": $timezone = "Europe/Volgograd"; break; case "18": $timezone = "Asia/Krasnoyarsk"; break; case "20": $timezone = "Asia/Irkutsk"; break; case "21": $timezone = "Europe/Moscow"; break; case "22": $timezone = "Europe/Volgograd"; break; case "23": $timezone = "Europe/Kaliningrad"; break; case "24": $timezone = "Europe/Volgograd"; break; case "25": $timezone = "Europe/Moscow"; break; case "26": $timezone = "Asia/Kamchatka"; break; case "27": $timezone = "Europe/Volgograd"; break; case "28": $timezone = "Europe/Moscow"; break; case "29": $timezone = "Asia/Novokuznetsk"; break; case "30": $timezone = "Asia/Vladivostok"; break; case "31": $timezone = "Asia/Krasnoyarsk"; break; case "32": $timezone = "Asia/Omsk"; break; case "33": $timezone = "Asia/Yekaterinburg"; break; case "34": $timezone = "Asia/Yekaterinburg"; break; case "35": $timezone = "Asia/Yekaterinburg"; break; case "36": $timezone = "Asia/Anadyr"; break; case "37": $timezone = "Europe/Moscow"; break; case "38": $timezone = "Europe/Volgograd"; break; case "39": $timezone = "Asia/Krasnoyarsk"; break; case "40": $timezone = "Asia/Yekaterinburg"; break; case "41": $timezone = "Europe/Moscow"; break; case "42": $timezone = "Europe/Moscow"; break; case "43": $timezone = "Europe/Moscow"; break; case "44": $timezone = "Asia/Magadan"; break; case "45": $timezone = "Europe/Samara"; break; case "46": $timezone = "Europe/Samara"; break; case "47": $timezone = "Europe/Moscow"; break; case "48": $timezone = "Europe/Moscow"; break; case "49": $timezone = "Europe/Moscow"; break; case "50": $timezone = "Asia/Yekaterinburg"; break; case "51": $timezone = "Europe/Moscow"; break; case "52": $timezone = "Europe/Moscow"; break; case "53": $timezone = "Asia/Novosibirsk"; break; case "54": $timezone = "Asia/Omsk"; break; case "55": $timezone = "Europe/Samara"; break; case "56": $timezone = "Europe/Moscow"; break; case "57": $timezone = "Europe/Samara"; break; case "58": $timezone = "Asia/Yekaterinburg"; break; case "59": $timezone = "Asia/Vladivostok"; break; case "60": $timezone = "Europe/Kaliningrad"; break; case "61": $timezone = "Europe/Volgograd"; break; case "62": $timezone = "Europe/Moscow"; break; case "63": $timezone = "Asia/Yakutsk"; break; case "64": $timezone = "Asia/Sakhalin"; break; case "65": $timezone = "Europe/Samara"; break; case "66": $timezone = "Europe/Moscow"; break; case "67": $timezone = "Europe/Samara"; break; case "68": $timezone = "Europe/Volgograd"; break; case "69": $timezone = "Europe/Moscow"; break; case "70": $timezone = "Europe/Volgograd"; break; case "71": $timezone = "Asia/Yekaterinburg"; break; case "72": $timezone = "Europe/Moscow"; break; case "73": $timezone = "Europe/Samara"; break; case "74": $timezone = "Asia/Krasnoyarsk"; break; case "75": $timezone = "Asia/Novosibirsk"; break; case "76": $timezone = "Europe/Moscow"; break; case "77": $timezone = "Europe/Moscow"; break; case "78": $timezone = "Asia/Yekaterinburg"; break; case "79": $timezone = "Asia/Irkutsk"; break; case "80": $timezone = "Asia/Yekaterinburg"; break; case "81": $timezone = "Europe/Samara"; break; case "82": $timezone = "Asia/Irkutsk"; break; case "83": $timezone = "Europe/Moscow"; break; case "84": $timezone = "Europe/Volgograd"; break; case "85": $timezone = "Europe/Moscow"; break; case "86": $timezone = "Europe/Moscow"; break; case "87": $timezone = "Asia/Novosibirsk"; break; case "88": $timezone = "Europe/Moscow"; break; case "89": $timezone = "Asia/Vladivostok"; break; } break; case "UA": switch ($region) { case "01": $timezone = "Europe/Kiev"; break; case "02": $timezone = "Europe/Kiev"; break; case "03": $timezone = "Europe/Uzhgorod"; break; case "04": $timezone = "Europe/Zaporozhye"; break; case "05": $timezone = "Europe/Zaporozhye"; break; case "06": $timezone = "Europe/Uzhgorod"; break; case "07": $timezone = "Europe/Zaporozhye"; break; case "08": $timezone = "Europe/Simferopol"; break; case "09": $timezone = "Europe/Kiev"; break; case "10": $timezone = "Europe/Zaporozhye"; break; case "11": $timezone = "Europe/Simferopol"; break; case "13": $timezone = "Europe/Kiev"; break; case "14": $timezone = "Europe/Zaporozhye"; break; case "15": $timezone = "Europe/Uzhgorod"; break; case "16": $timezone = "Europe/Zaporozhye"; break; case "17": $timezone = "Europe/Simferopol"; break; case "18": $timezone = "Europe/Zaporozhye"; break; case "19": $timezone = "Europe/Kiev"; break; case "20": $timezone = "Europe/Simferopol"; break; case "21": $timezone = "Europe/Kiev"; break; case "22": $timezone = "Europe/Uzhgorod"; break; case "23": $timezone = "Europe/Kiev"; break; case "24": $timezone = "Europe/Uzhgorod"; break; case "25": $timezone = "Europe/Uzhgorod"; break; case "26": $timezone = "Europe/Zaporozhye"; break; case "27": $timezone = "Europe/Kiev"; break; } break; case "UZ": switch ($region) { case "01": $timezone = "Asia/Tashkent"; break; case "02": $timezone = "Asia/Samarkand"; break; case "03": $timezone = "Asia/Tashkent"; break; case "06": $timezone = "Asia/Tashkent"; break; case "07": $timezone = "Asia/Samarkand"; break; case "08": $timezone = "Asia/Samarkand"; break; case "09": $timezone = "Asia/Samarkand"; break; case "10": $timezone = "Asia/Samarkand"; break; case "12": $timezone = "Asia/Samarkand"; break; case "13": $timezone = "Asia/Tashkent"; break; case "14": $timezone = "Asia/Tashkent"; break; } break; case "TL": $timezone = "Asia/Dili"; break; case "PF": $timezone = "Pacific/Marquesas"; break; } return $timezone; } function normalizeURI($uri) { $uri=quoted_printable_decode($uri); if (preg_match("/^(.*)/",$uri,$m)) { if (preg_match("/^(.*):/U",$m[2],$p)){ $uri=$m[1]."@".$p[1].">"; } else { $uri=$m[1]."@".$m[2]; } } else if (preg_match("/^(sips?:.*)[=:;]/U",$uri,$p)) { $uri=$p[1]; } return $uri; } function normalizeTime($period) { $sec=$period%60; $min=floor($period/60); $h=floor($min/60); if (!$period) return ; if ($h>0) { $min=$min-60*$h; } if ($h >= 1) { return sprintf('%dh%02d\'%02d"', $h, $min, $sec); } else { return sprintf('%d\'%02d"', $min, $sec); } } function checkURI($uri) { //dprint ("checkURI($uri) "); if ($uri == "") return true; if (preg_match("/^(sip:|sips:)(.*)$/",$uri,$m)) $uri=$m[2]; $regexp = "/^(\+?[a-z0-9*][a-z0-9_.*-]*)@([a-z0-9][a-z0-9-]*\.)+(([a-z]{2,})|(\d+))$/i"; if (stristr($uri,"-.") || !preg_match($regexp, $uri)) { print "Invalid URI \"$uri\". "; return false; } return true; } function checkPhonebookURI($uri) { $regexp = "/^sip:([a-z0-9%_.-]*)@([a-z0-9%.-]*)$/i"; if (stristr($contact,"-.") || !preg_match($regexp, $uri)) { print "Invalid URI \"$uri\". "; return false; } return true; } function getLocalTime($timezone, $timestamp) { $tz = getenv('TZ'); putenv("TZ=$timezone"); if (!$timestamp) { return; } $LocalTime = date("Y-m-d H:i:s", $timestamp); putenv("TZ=$tz"); return $LocalTime; } function getSipThorHomeNode ($account,$sip_proxy) { if (!$account || !$sip_proxy) return false; $socket = fsockopen($sip_proxy, 9500, $errno, $errstr, 1); if (!$socket) { return false; } $request=sprintf("lookup sip_proxy for %s",$account); if (fputs($socket,"$request\r\n") !== false) { $ret = fgets($socket,4096); } fclose($socket); return $ret; } function getSipAccountFromX509Certificate($account='') { if (!$account) { print _('Error, please specify an account'); return false; } list($username, $domain) = explode("@",$account); if (!$username || !$domain) { print _("Invalid account provided"); return false; } if (!$_SERVER[SSL_CLIENT_CERT]) { print _("Error: No X.509 client certificate provided\n"); return false; } if (!$cert=openssl_x509_parse($_SERVER[SSL_CLIENT_CERT])) { print _("Error: Failed to parse X.509 client certificate\n"); return false; } require("/etc/cdrtool/ngnpro_engines.inc"); global $domainFilters, $resellerFilters, $soapEngines; if ($domainFilters[$domain]['sip_engine']) { $credentials['engine'] = $domainFilters[$domain]['sip_engine']; $credentials['customer'] = $domainFilters[$domain]['customer']; $credentials['reseller'] = $domainFilters[$domain]['reseller']; } else if ($domainFilters['default']['sip_engine']) { $credentials['engine']=$domainFilters['default']['sip_engine']; } else { print "Error: no domainFilter available in ngnpro_engines.inc"; return false; } $SOAPlogin=array( "username" => $soapEngines[$credentials['engine']]['username'], "password" => $soapEngines[$credentials['engine']]['password'], "admin" => true ); $SoapAuth = array('auth', $SOAPlogin , 'urn:AGProjects:NGNPro', 0, ''); $SipPort = new WebService_NGNPro_SipPort($soapEngines[$credentials['engine']]['url']); $SipPort->_options['timeout'] = 5; $SipPort->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0); $SipPort->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0); $SipPort->addHeader($SoapAuth); // Filter $filter=array('username' => $username, 'domain' => $domain, 'owner' => intval($cert['subject']['CN']) ); // Range $range=array('start' => 0, 'count' => 10 ); $orderBy = array('attribute' => 'changeDate', 'direction' => 'DESC' ); // Compose query $Query=array('filter' => $filter, 'orderBy' => $orderBy, 'range' => $range ); // Call function $result = $SipPort->getAccounts($Query); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

    Error from %s (SipPort): %s (%s): %s",$soapEngines[$credentials['engine']]['url'],$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } if ($result->total != 1) { return false; } $credentials['account'] = $account; $credentials['customer'] = $result->customer; $credentials['reseller'] = $result->reseller; return $credentials; } function getSipAccountFromHTTPDigest () { require("/etc/cdrtool/enrollment/config.ini"); if (!is_array($enrollment) || !strlen($enrollment['nonce_key'])) { $log= 'Error: Missing nonce in enrollment settings'; syslog(LOG_NOTICE, $log); die($log); return false; } if ($_REQUEST['realm']) { // required by Blink cocoa $realm=$_REQUEST['realm']; $a=explode("@",$realm); if (count($a) == 2) { $realm = $a[1]; } } else { $realm = 'SIP_settings'; } // security implemented based on // http://static.springsource.org/spring-security/site/docs/2.0.x/reference/digest.html $_id = microtime(true)+ 300; // expires 5 minutes in the future $_key = $enrollment['nonce_key']; $nonce = base64_encode($_id.":".md5($_id.":".$_key)); if (empty($_SERVER['PHP_AUTH_DIGEST'])) { header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Digest realm="'.$realm. '",qop="auth",nonce="'.$nonce.'",opaque="'.md5($realm).'"'); //syslog(LOG_NOTICE, sprintf ("SIP settings page: sent auth request for realm %s to %s", $realm, $_SERVER['REMOTE_ADDR'])); die(); } // analyze the PHP_AUTH_DIGEST variable if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($data['username'])) { $log=sprintf("SIP settings page: Invalid credentials from %s", $_SERVER['REMOTE_ADDR']); syslog(LOG_NOTICE, $log); die($log); } // generate the valid response $username = $data['username']; if (strstr($username, '@')) { $a = explode("@",$username); $username = $a[0]; $domain = $a[1]; } else { $domain = $realm; } require("/etc/cdrtool/ngnpro_engines.inc"); global $domainFilters, $resellerFilters, $soapEngines ; $credentials['account'] = sprintf("%s@%s",$username, $domain); if ($domainFilters[$domain]['sip_engine']) { $credentials['engine'] = $domainFilters[$domain]['sip_engine']; $credentials['customer'] = $domainFilters[$domain]['customer']; $credentials['reseller'] = $domainFilters[$domain]['reseller']; } else if ($domainFilters['default']['sip_engine']) { $credentials['engine']=$domainFilters['default']['sip_engine']; } else { $log=sprintf("SIP settings page error: no domainFilter available in ngnpro_engines.inc from %s", $_SERVER['REMOTE_ADDR']); syslog(LOG_NOTICE, $log); die(); } $SOAPlogin=array( "username" => $soapEngines[$credentials['engine']]['username'], "password" => $soapEngines[$credentials['engine']]['password'], "admin" => true ); $SoapAuth = array('auth', $SOAPlogin , 'urn:AGProjects:NGNPro', 0, ''); $SipPort = new WebService_NGNPro_SipPort($soapEngines[$credentials['engine']]['url']); $SipPort->_options['timeout'] = 5; $SipPort->setOpt('curl', CURLOPT_SSL_VERIFYPEER, 0); $SipPort->setOpt('curl', CURLOPT_SSL_VERIFYHOST, 0); $SipPort->addHeader($SoapAuth); $result = $SipPort->getAccount(array("username" =>$username,"domain" =>$domain)); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Digest realm="'.$realm. '",qop="auth",nonce="'.$nonce.'",opaque="'.md5($realm).'"'); $log=sprintf("SIP settings page error: non-existent username %s from %s", $credentials['account'], $_SERVER['REMOTE_ADDR']); syslog(LOG_NOTICE, $log); die(); } $web_password=''; foreach ($result->properties as $_property) { if ($_property->name == 'web_password') { //$web_password = explode(":", $_property->value, -1); $split=explode(":",$_property->value); $web_password=$split['0']; break; } } if (!empty($web_password)) { //$A1 = md5($data['username'] . ':' . $realm . ':' . $data['password']); $A1 = $web_password; $login_type_log = 'web password'; //$log=sprintf("TEST %s %s %s %s", $data['username'], $realm, $web_password , $data['nonce']); //syslog(LOG_NOTICE, $log); // } else if (strstr($data['username'], '@')) { // $A1 = md5($data['username'] . ':' . $realm . ':' . $result->password); // $login_type_log = 'cleartext legacy password'; } else if ($result->ha1) { $login_type_log = sprintf('encrypted password'); $A1 = $result->ha1; } else { $A1 = md5($data['username'] . ':' . $realm . ':' . $result->password); $login_type_log = 'cleartext password'; } $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']); $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2); if ($data['response'] != $valid_response ) { header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Digest realm="'.$realm. '",qop="auth",nonce="'.$nonce.'",opaque="'.md5($realm).'"'); $log=sprintf("SIP settings page error: wrong credentials using %s for %s from %s", $login_type_log, $credentials['account'], $_SERVER['REMOTE_ADDR']); syslog(LOG_NOTICE, $log); die(); } // check nonce $client_nonce_els=explode(":",base64_decode($data['nonce'])); if (md5($client_nonce_els[0].":".$_key) != $client_nonce_els[1]) { header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Digest realm="'.$realm. '",qop="auth",nonce="'.$nonce.'",opaque="'.md5($realm).'"'); $log=sprintf("SIP settings page error: wrong nonce for %s from %s", $credentials['account'], $_SERVER['REMOTE_ADDR']); syslog(LOG_NOTICE, $log); die(); } if (microtime(true) > $client_nonce_els[0]) { // nonce is stale header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Digest realm="'.$realm. '",qop="auth",nonce="'.$nonce.'",stale=true,opaque="'.md5($realm).'"'); $log=sprintf("SIP settings page error: nonce has expired for %s from %s", $username, $_SERVER['REMOTE_ADDR']); syslog(LOG_NOTICE, $log); die(); } $log=sprintf("SIP settings page: %s logged in using %s from %s", $credentials['account'], $login_type_log, $_SERVER['REMOTE_ADDR']); syslog(LOG_NOTICE, $log); $credentials['customer'] = $result->customer; $credentials['reseller'] = $result->reseller; return $credentials; } function http_digest_parse($txt) { // function to parse the http auth header // protect against missing data $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1); $data = array(); $keys = implode('|', array_keys($needed_parts)); preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER); foreach ($matches as $m) { $data[$m[1]] = $m[3] ? $m[3] : $m[4]; unset($needed_parts[$m[1]]); } return $needed_parts ? false : $data; } function renderUI($SipSettings_class,$account,$login_credentials,$soapEngines) { // Generic code for all sip settings pages $SipSettings = new $SipSettings_class($account,$login_credentials,$soapEngines); if ($_REQUEST['action']) { $log_action=$_REQUEST['action']; } else { $log_action='load main page'; } $log=sprintf("SIP settings page: %s for %s from %s", $log_action, $account, $_SERVER['REMOTE_ADDR']); syslog(LOG_NOTICE, $log); if (!strstr($_REQUEST['action'],'get_') && !strstr($_REQUEST['action'],'set_') && !strstr($_REQUEST['action'],'put_') && !strstr($_REQUEST['action'],'delete_') && !strstr($_REQUEST['action'],'export_') && !strstr($_REQUEST['action'],'add_')) { $title = "$account"; if (array_key_exists($SipSettings->tab, $SipSettings->tabs)) { $title = $SipSettings->tabs[$SipSettings->tab]. " - ". $title; } $header = $SipSettings->headerFile; $css = $SipSettings->cssFile; $auto_refesh_tab=$SipSettings->auto_refesh_tab; $absolute_url= $SipSettings->absolute_url; include($header); dprint("Header file $header included, refresh=$auto_refesh_tab"); include($css); dprint("CSS file $css included"); } if ($_REQUEST['action']=="save settings") { if ($SipSettings->checkSettings()) { $SipSettings->saveSettings(); unset($SipSettings); $SipSettings = new $SipSettings_class($account,$login_credentials,$soapEngines); } else { print ""; printf (_("Error: %s"),$SipSettings->error); print ""; } } else if ($_REQUEST['action']=="set diversions") { $SipSettings->setDiversions(); unset($SipSettings); $SipSettings = new $SipSettings_class($account,$login_credentials,$soapEngines); } else if ($_REQUEST['action']=="set barring") { $SipSettings->setBarringPrefixes(); } else if ($_REQUEST['action']=="set reject") { $SipSettings->setRejectMembers(); } else if ($_REQUEST['action']=="set accept rules") { $SipSettings->setAcceptRules(); } else if ($_REQUEST['action']=="set aliases") { $SipSettings->setAliases(); } else if ($_REQUEST['action']=="send email") { $SipSettings->sendEmail(); } else if ($_REQUEST['action']=="delete account") { $SipSettings->deleteAccount(); } else if ($_REQUEST['action']=="delete_account") { // print "

    ";
            // print_r($SipSettings->Preferences);
             $date1= new datetime($SipSettings->Preferences['account_delete_request']);
             $today= new datetime('now');
             if ($date1->diff($today)->d <= '2' && $SipSettings->Preferences['account_delete_request'] ) {
     
                 $SipSettings->SipPort->addHeader($SipSettings->SoapAuth);
                 $result = $SipSettings->SipPort->deleteAccount($SipSettings->sipId);
     
                 if ((new PEAR)->isError($result)) {
                     $error_msg  = $result->getMessage();
                     $error_fault= $result->getFault();
                     $error_code = $result->getCode();
                     $_msg=sprintf ("Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring);
                     $return=array('success'       => false,
                                 'error_message' => $_msg
                                 );
                     return false;
                 }  else {
                     printf("

    The account %s has been removed

    ",$SipSettings->account); $SipSettings->sendRemoveAccount(); //print "" print ""; print _("Click here to Logout"); print ""; //$auth->logout(); //$sess->delete(); return true; } } else { printf("The delete request for account %s has expired or is not valid",$SipSettings->account); return false; } return true ; //$SipSettings->deleteAccount(); } else if ($_REQUEST['action']=="get_crt") { $SipSettings->exportCertificateX509(); return true; } else if ($_REQUEST['action']=="get_p12") { $SipSettings->exportCertificateP12(); return true; } else if ($_REQUEST['action'] == 'get_balance_history') { $SipSettings->getBalanceHistory(); if ($_REQUEST['csv']) { $SipSettings->exportBalanceHistory(); } else { print json_encode($SipSettings->balance_history); } return true; } else if ($_REQUEST['action'] == 'get_call_forwarding') { $SipSettings->getDiversions(); print json_encode($SipSettings->diversions); return true; } else if ($_REQUEST['action'] == 'get_prepaid') { $SipSettings->getPrepaidStatus(); print json_encode($SipSettings->prepaidAccount); return true; } else if ($_REQUEST['action'] == 'get_monthly_usage') { $SipSettings->getCallStatistics(); print json_encode($SipSettings->thisMonth); return true; } else if ($_REQUEST['action'] == 'get_accept_rules'){ $SipSettings->getAcceptRules(); print json_encode($SipSettings->acceptRules); return true; } else if ($_REQUEST['action'] == 'get_journal_entries'){ $SipSettings->getJournalEntries(); print json_encode($SipSettings->journalEntries); return true; } else if ($_REQUEST['action'] == 'put_journal_entries'){ print json_encode($SipSettings->putJournalEntries()); return true; } else if ($_REQUEST['action'] == 'delete_journal_entries'){ print json_encode($SipSettings->deleteJournalEntries()); return true; } else if ($_REQUEST['action'] == 'get_reject_rules'){ $SipSettings->getRejectMembers(); print json_encode($SipSettings->rejectMembers); return true; } else if ($_REQUEST['action'] == 'get_history'){ $SipSettings->getHistory('completed'); print json_encode($SipSettings->call_history); return true; } else if ($_REQUEST['action'] == 'get_voicemail'){ $SipSettings->getVoicemail(); print json_encode($SipSettings->voicemail); return true; } else if ($_REQUEST['action'] == 'get_aliases'){ $SipSettings->getAliases(); print json_encode($SipSettings->aliases); return true; } else if ($_REQUEST['action'] == 'get_enum'){ $SipSettings->getEnumMappings(); print json_encode($SipSettings->enums); return true; } else if ($_REQUEST['action'] == 'export_identity_proof'){ $SipSettings->exportIdentityProof(); return true; } else if ($_REQUEST['action'] == 'add_balance'){ if (!$_REQUEST['id'] || !$_REQUEST['number']) { $return=array('success' => false, 'error_message' => 'Missing id or number' ); print (json_encode($return)); return false; } $card = array('id' => intval($_REQUEST['id']), 'number' => $_REQUEST['number'] ); $SipSettings->SipPort->addHeader($SipSettings->SoapAuth); $result = $SipSettings->SipPort->addBalanceFromVoucher($SipSettings->sipId,$card); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); $_msg=sprintf ("Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); $return=array('success' => false, 'error_message' => $_msg ); print (json_encode($return)); return false; } else { $return=array('success' => true, 'error_message' => 'Added balance succeeded' ); print (json_encode($return)); return true; } } else if ($_REQUEST['action'] == 'get_identity'){ $account=array('sip_address' => $SipSettings->account, 'email' => $SipSettings->email, 'first' => $SipSettings->firstName, 'lastname' => $SipSettings->lastName, 'pstn_caller_id' => $SipSettings->rpid, 'mobile_number' => $SipSettings->mobile_number, 'timezone' => $SipSettings->timezone, 'no_answer_timeout' => $SipSettings->timeout, 'quick_dial' => $SipSettings->quickdial ); print json_encode($account); return true; } else if ($_REQUEST['action'] == 'get_devices'){ $SipSettings->SipPort->addHeader($SipSettings->SoapAuth); $result = $SipSettings->SipPort->getSipDeviceLocations(array($SipSettings->sipId)); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); $_msg=sprintf ("Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); $_ret=false; $return=array('success' => $_ret, 'error_message' => $_msg ); print (json_encode($return)); return false; } else { foreach ($result[0]->locations as $locationStructure) { $contact=$locationStructure->address.":".$locationStructure->port; if ($locationStructure->publicAddress) { $publicContact=$locationStructure->publicAddress.":".$locationStructure->publicPort; } else { $publicContact=$contact; } $devices[]=array("contact" => $contact, "publicContact" => $publicContact, "expires" => $locationStructure->expires, "user_agent" => $locationStructure->userAgent, "transport" => $locationStructure->transport ); } } print (json_encode($devices)); return true; } else if ($_REQUEST['action'] == 'set_dnd_on'){ $SipSettings->getAcceptRules(); $SipSettings->acceptRules['temporary']=array('groups' =>array('nobody'), 'duration' =>intval($_REQUEST['duration']) ); $SipSettings->SipPort->addHeader($SipSettings->SoapAuth); $result = $SipSettings->SipPort->setAcceptRules($SipSettings->sipId,$SipSettings->acceptRules); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); $_msg=sprintf ("Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); $_ret=false; } else { $_ret=true; if (intval($_REQUEST['duration'] > 0)) { $_msg=sprintf(_('Do not disturb has been enabled for %d minutes'),intval($_REQUEST['duration'])); } else { $_msg=sprintf(_('Do not disturb has been enabled')); } } $return=array('success' => $_ret, 'error_message' => $_msg ); print (json_encode($return)); return true; } else if ($_REQUEST['action'] == 'set_dnd_off'){ $SipSettings->getAcceptRules(); $SipSettings->acceptRules['temporary']=array('groups' =>array('everybody'), 'duration' =>0 ); $SipSettings->SipPort->addHeader($SipSettings->SoapAuth); $result = $SipSettings->SipPort->setAcceptRules($SipSettings->sipId,$SipSettings->acceptRules); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); $_msg=sprintf ("Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); $_ret=false; } else { $_ret=true; $_msg=sprintf(_('Do not disturb has been disabled')); } $return=array('success' => $_ret, 'error_message' => $_msg ); print (json_encode($return)); return true; } else if ($_REQUEST['action'] == 'set_privacy_on'){ $SipSettings->SipPort->addHeader($SipSettings->SoapAuth); $result = $SipSettings->SipPort->addToGroup(array("username" => $SipSettings->username,"domain"=> $SipSettings->domain),"anonymous"); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); $_msg=sprintf ("Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); $_ret=false; } else { $_ret=true; $_msg=sprintf(_('Caller-ID is now hidden for outgoing calls')); } $return=array('success' => $_ret, 'error_message' => $_msg ); print (json_encode($return)); return true; } else if ($_REQUEST['action'] == 'set_privacy_off'){ $SipSettings->SipPort->addHeader($SipSettings->SoapAuth); $result = $SipSettings->SipPort->removeFromGroup(array("username" => $SipSettings->username,"domain"=> $SipSettings->domain),"anonymous"); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); if ($error_fault->detail->exception->errorcode == 1031) { $_ret=true; $_msg=sprintf(_('Caller-ID is now visible for outgoing calls')); } else { $_msg=sprintf ("Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); $_ret=false; } } else { $_ret=true; $_msg=sprintf(_('Caller-ID is now visible for outgoing calls')); } $return=array('success' => $_ret, 'error_message' => $_msg ); print (json_encode($return)); return true; } else if ($_REQUEST['action'] == 'add_alias'){ $SipSettings->SipPort->addHeader($SipSettings->SoapAuth); $username=trim($_REQUEST['username']); if (!strlen($username)) { $return=array('success' => false, 'error_message' => 'Error: missing username' ); print (json_encode($return)); return false; } $_aliasObject=array("id"=>array("username"=>strtolower($username), "domain"=>$SipSettings->domain ), "owner" => intval($SipSettings->owner), "target"=> array("username" => $SipSettings->username,"domain"=> $SipSettings->domain) ) ; $result = $SipSettings->SipPort->addAlias($_aliasObject); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); $_msg=sprintf ("Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); $_ret=false; } else { $_ret=true; $_msg=sprintf(_('Added alias %s'),strtolower($username)); } $return=array('success' => $_ret, 'error_message' => $_msg ); print (json_encode($return)); return true; } else if ($_REQUEST['action'] == 'set_call_forwarding') { $SipSettings->SipPort->addHeader($SipSettings->SoapAuth); $result = $SipSettings->SipPort->getCallDiversions($SipSettings->sipId); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); $_msg=sprintf ("Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); $_ret=false; $return=array('success' => $_ret, 'error_message' => $_msg ); print (json_encode($return)); return true; } $SipSettings->getVoicemail(); foreach(array_keys($SipSettings->diversionType) as $condition) { $old_diversions[$condition]=$result->$condition; } $_log=''; foreach(array_keys($old_diversions) as $key) { if (isset($_REQUEST[$key])) { printf ("Key $key changed %s",$_REQUEST[$key]); $textboxURI=$_REQUEST[$key]; if ($textboxURI == "" && strlen($SipSettings->mobile_number)) { $textboxURI = $SipSettings->mobile_number; } if ($textboxURI && $textboxURI != "" && !preg_match("/@/",$textboxURI)) { $textboxURI=$textboxURI."@".$SipSettings->domain; } if (preg_match("/^([\+|0].*)@/",$textboxURI,$m)) { $textboxURI=$m[1]."@".$SipSettings->domain; } if (strlen($textboxURI) && $textboxURI != "" && !preg_match("/^sip:/",$textboxURI)) { $textboxURI='sip:'.$textboxURI; } if ($textboxURI) { $new_diversions[$key]=$textboxURI; } $_log.=sprintf("%s=%s ",$key,$textboxURI); $divert_changed=true; } else { if ($old_diversions[$key]) { $new_diversions[$key]=$old_diversions[$key]; } } } if ($divert_changed) { $SipSettings->SipPort->addHeader($SipSettings->SoapAuth); $result = $SipSettings->SipPort->setCallDiversions($SipSettings->sipId,$new_diversions); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); $_msg=sprintf ("Error (SipPort): %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); $_ret=false; } else { $_ret=true; $_msg=sprintf(_('Changed diversions %s'),$_log); } $return=array('success' => $_ret, 'error_message' => $_msg ); print (json_encode($return)); return true; } else { $return=array('success' => true, 'error_message' => 'Diversions remained the same' ); print (json_encode($return)); return true; } } else if ($_REQUEST['action']) { $return=array('success' => false, 'error_message' => "Error: invalid action" ); print (json_encode($return)); return false; } if (!$_REQUEST['export']) { $SipSettings->showAccount(); print " "; } } class Enrollment { var $init = false; var $create_voicemail = false; var $send_email_notification = true; var $create_email_alias = false; var $create_customer = true; var $timezones = array(); var $default_timezone = 'Europe/Amsterdam'; var $configuration_file = '/etc/cdrtool/enrollment/config.ini'; var $allow_pstn = 1; var $quota = 50; var $prepaid = 1; var $create_certificate = 0; var $customer_belongs_to_reseller = false; function log_action($action){ global $auth; $location = "Unknown"; $_loc=geoip_record_by_name($_SERVER['REMOTE_ADDR']); if ($_loc['country_name']) { $location = $_loc['country_name']; } $log = sprintf("CDRTool login username=%s, IP=%s, location=%s, action=%s, script=%s", $auth->auth["uname"], $_SERVER['REMOTE_ADDR'], $location, $action, $_SERVER['PHP_SELF'] ); syslog(LOG_NOTICE, $log); } function Enrollment() { require($this->configuration_file); require("/etc/cdrtool/ngnpro_engines.inc"); $this->soapEngines = $soapEngines; $this->enrollment = $enrollment; $this->loadTimezones(); if (!is_array($this->soapEngines)) { $return=array('success' => false, 'error_message' => 'Error: Missing soap engines configuration' ); print (json_encode($return)); return false; } if (!is_array($this->enrollment)) { $return=array('success' => false, 'error_message' => 'Error: Missing enrollment configuration' ); print (json_encode($return)); return false; } $this->sipDomain = $this->enrollment['sip_domain']; $this->sipEngine = $this->enrollment['sip_engine']; if ($this->enrollment['timezone']) { $this->default_timezone = $this->enrollment['timezone']; } if ($this->enrollment['customer_engine']) { $this->customerEngine = $this->enrollment['customer_engine']; } else { $this->customerEngine = $this->enrollment['sip_engine']; } if ($this->enrollment['email_engine']) { $this->emailEngine = $this->enrollment['email_engine']; } else { $this->emailEngine = $this->enrollment['sip_engine']; } if (is_array($this->enrollment['groups'])) { $this->groups = $this->enrollment['groups']; } else { $this->groups = array(); } $this->reseller = $this->enrollment['reseller']; $this->outbound_proxy = $this->enrollment['outbound_proxy']; $this->xcap_root = $this->enrollment['xcap_root']; $this->msrp_relay = $this->enrollment['msrp_relay']; $this->settings_url = $this->enrollment['settings_url']; $this->ldap_hostname = $this->enrollment['ldap_hostname']; $this->ldap_dn = $this->enrollment['ldap_dn']; $this->conference_server = $this->enrollment['conference_server']; if ($this->enrollment['sip_class']) { $this->sipClass = $this->enrollment['sip_class']; } else { $this->sipClass = 'SipSettings'; } if (!$this->sipEngine) { $return=array('success' => false, 'error_message' => 'Missing sip engine' ); print (json_encode($return)); return false; } if (!$this->sipDomain) { $return=array('success' => false, 'error_message' => 'Missing sip domain' ); print (json_encode($return)); return false; } $this->sipLoginCredentials = array( 'reseller' => intval($this->reseller), 'sip_engine' => $this->sipEngine, 'login_type' => 'admin' ); $this->init=true; } function createAccount() { if (!$this->init) return false; if (!$_REQUEST['email']) { $return=array('success' => false, 'error' => 'value_error', 'error_message' => 'Missing email address' ); print (json_encode($return)); return false; } if (!$this->checkEmail($_REQUEST['email'])) { $return=array('success' => false, 'error' => 'value_error', 'error_message' => 'Invalid email address' ); print (json_encode($return)); return false; } if (!$_REQUEST['password']) { $return=array('success' => false, 'error' => 'value_error', 'error_message' => 'Missing password' ); print (json_encode($return)); return false; } if (!$_REQUEST['display_name']) { $return=array('success' => false, 'error' => 'value_error', 'error_message' => 'Missing display name' ); print (json_encode($return)); return false; } $username=strtolower(trim($_REQUEST['username'])); if (!preg_match("/^[1-9a-z][0-9a-z_.-]{2,64}[0-9a-z]$/",$username)) { $return=array('success' => false, 'error' => 'value_error', 'error_message' => 'The username must contain at least 4 lowercase alpha-numeric . _ or - characters and must start and end with a positive digit or letter' ); print (json_encode($return)); return false; } $sip_address=$username.'@'.$this->sipDomain; if ($this->create_customer && !$_REQUEST['owner']) { // create owner id $customerEngine = 'customers@'.$this->customerEngine; $this->CustomerSoapEngine = new SoapEngine($customerEngine,$this->soapEngines,$this->customerLoginCredentials); $_customer_class = $this->CustomerSoapEngine->records_class; $this->customerRecords = new $_customer_class($this->CustomerSoapEngine); $this->customerRecords->html=false; $properties=$this->customerRecords->setInitialCredits(array('sip_credit' => 1, 'sip_alias_credit' => 1, 'email_credit' => 1 ) ); if (preg_match("/^(\w+)\s+(\w+)$/",$_REQUEST['display_name'],$m)) { $firstName = $m[1]; $lastName = $m[2]; } else { $firstName = $_REQUEST['display_name']; $lastName = 'Blink'; } $this->log_action("Create owner account ($firstname $lastname) "); $timezone=$_REQUEST['tzinfo']; if (!in_array($timezone, $this->timezones)) { $timezone=$this->default_timezone; } $location = lookupGeoLocation($_SERVER['REMOTE_ADDR']); $customer=array( 'firstName' => $firstName, 'lastName' => $lastName, 'timezone' => $timezone, 'password' => trim($_REQUEST['password']), 'email' => trim($_REQUEST['email']), 'country' => $location['country_code'], 'state' => utf8_encode($location['region']), 'city' => utf8_encode($location['city']), 'properties' => $properties ); if ($this->customer_belongs_to_reseller) { $customer['reseller'] =intval($this->reseller); } if ($location['country_code'] == 'NL') { $customer['tel'] = '+31999999999'; } else if ($location['country_code'] == 'US') { $customer['tel'] = sprintf ("+1%s9999999",$location['area_code']); } else { $customer['tel'] = '+19999999999'; } $_customer_created=false; $j=0; while ($j < 3) { $username.=RandomString(4); $customer['username']=$username; if (!$result = $this->customerRecords->addRecord($customer)) { if ($this->customerRecords->SoapEngine->exception->errorcode != "5001") { $return=array('success' => false, 'error' => 'internal_error', 'error_message' => 'failed to create non-duplicate customer entry' ); print (json_encode($return)); return false; } } else { $_customer_created=true; break; } $j++; } if (!$_customer_created) { if ($this->sipRecords->soap_error_description) { $_msg=$this->sipRecords->soap_error_description; } else { $_msg='failed to create customer account'; } $return=array('success' => false, 'error' => 'internal_error', 'error_message' => $_msg ); print (json_encode($return)); return false; } else { $this->log_action("Owner account created (". $customer['username'].")"); } $owner=$result->id; if (!$owner) { $return=array('success' => false, 'error' => 'internal_error', 'error_message' => 'failed to obtain a new owner id' ); print (json_encode($return)); return false; } else { $this->log_action("Owner id is $owner (". $customer['username'].")"); } } else if (is_numeric($_REQUEST['owner']) && $_REQUEST['owner'] != 0 ) { $owner=intval($_REQUEST['owner']); } else { $return=array('success' => false, 'error' => 'internal_error', 'error_message' => 'no owner information provided' ); print (json_encode($return)); return false; } // create SIP Account $sipEngine = 'sip_accounts@'.$this->sipEngine; $this->SipSoapEngine = new SoapEngine($sipEngine,$this->soapEngines,$this->sipLoginCredentials); $_sip_class = $this->SipSoapEngine->records_class; $this->sipRecords = new $_sip_class($this->SipSoapEngine); $this->sipRecords->html=false; $sip_properties[]=array('name'=> 'ip', 'value' => $_SERVER['REMOTE_ADDR']); $sip_properties[]=array('name'=> 'registration_email', 'value' => $_REQUEST['email']); $languages=array("en","ro","nl","es","de"); if (isset($_REQUEST['lang'])){ if (in_array($_REQUEST['lang'],$languages)) { $sip_properties[]=array('name'=> 'language', 'value' => $_REQUEST['lang']); } } if (strlen($timezone)) { $sip_properties[]=array('name'=> 'timezone', 'value' => $timezone); } if (strlen($user_agent)) { $sip_properties[]=array('name'=> 'user_agent', 'value' => trim(urldecode($user_agent))); } $sipAccount = array('account' => $sip_address, 'fullname' => $_REQUEST['display_name'], 'email' => $_REQUEST['email'], 'password' => $_REQUEST['password'], 'timezone' => $timezone, 'prepaid' => $this->prepaid, 'pstn' => $this->allow_pstn, 'quota' => $this->quota, 'owner' => intval($owner), 'groups' => $this->groups, 'properties'=> $sip_properties ); $this->log_action("Create SIP account ($sip_addres)"); if (!$result = $this->sipRecords->addRecord($sipAccount)) { if ($this->sipRecords->SoapEngine->exception->errorstring) { if ($this->sipRecords->SoapEngine->exception->errorcode == 1011) { $return=array('success' => false, 'error' => 'user_exists', 'error_message' => $this->sipRecords->SoapEngine->exception->errorstring ); } else { $return=array('success' => false, 'error' => 'internal_error', 'error_message' => $this->sipRecords->SoapEngine->exception->errorstring ); } } else { $_msg='failed to create sip account'; $return=array('success' => false, 'error' => 'internal_error', 'error_message' => $_msg ); } print (json_encode($return)); $_dictionary=array('customer'=>intval($owner), 'error' => 'internal_error', 'confirm' => true ); $this->customerRecords->deleteRecord($_dictionary); return false; } else { $sip_address=$result->id->username.'@'.$result->id->domain; $this->log_action("SIP account created ($sip_address)"); if ($this->create_certificate) { if (!$passport = $this->generateCertificate($sip_address,$_REQUEST['email'],$_REQUEST['password'])) { $return=array('success' => false, 'error' => 'internal_error', 'error_message' => 'failed to generate certificate' ); print (json_encode($return)); return false; } } // Generic code for all sip settings pages if ($this->create_voicemail || $this->send_email_notification) { if ($SipSettings = new $this->sipClass($sip_address,$this->sipLoginCredentials,$this->soapEngines)) { if ($this->create_voicemail) { // Add voicemail account $this->log_action("Add voicemail account ($sip_address)"); $SipSettings->addVoicemail(); $SipSettings->setVoicemailDiversions(); } if ($this->send_email_notification) { // Sent account settings by email $SipSettings->sendEmail('hideHtml'); } } } if ($this->create_email_alias) { $this->log_action("Add email alias ($sip_address)"); $emailEngine = 'email_aliases@'.$this->emailEngine; $this->EmailSoapEngine = new SoapEngine($emailEngine,$this->soapEngines,$this->sipLoginCredentials); $_email_class = $this->EmailSoapEngine->records_class; $this->emailRecords = new $_email_class($this->EmailSoapEngine); $this->emailRecords->html=false; $emailAlias = array('name' => strtolower($sip_address), 'type' => 'MBOXFW', 'owner' => intval($owner), 'value' => $_REQUEST['email'] ); $this->emailRecords->addRecord($emailAlias); } $return=array('success' => true, 'sip_address' => $sip_address, 'email' => $result->email, 'settings_url' => $this->settings_url, 'outbound_proxy' => $this->outbound_proxy ); if ($this->create_certificate) { $return['passport'] = $passport; } if ($this->ldap_hostname) { $return['ldap_hostname'] = $this->ldap_hostname; } if ($this->ldap_dn) { $return['ldap_dn'] = $this->ldap_dn; } if ($this->msrp_relay) { $return['msrp_relay'] = $this->msrp_relay; } if ($this->xcap_root) { $return['xcap_root'] = $this->xcap_root; } if ($this->conference_server) { $return['conference_server'] = $this->conference_server; } print (json_encode($return)); return true; } } function generateCertificate($sip_address,$email,$password) { if (!$this->init) return false; if (!is_array($this->enrollment)) { print _("Error: missing enrollment settings"); return false; } if (!$this->enrollment['ca_conf']) { //print _("Error: missing enrollment ca_conf settings"); return false; } if (!$this->enrollment['ca_crt']) { //print _("Error: missing enrollment ca_crt settings"); return false; } if (!$this->enrollment['ca_key']) { //print _("Error: missing enrollment ca_key settings"); return false; } $config = array( 'config' => $this->enrollment['ca_conf'], 'digest_alg' => 'md5', 'private_key_bits' => 1024, 'private_key_type' => OPENSSL_KEYTYPE_RSA, 'encrypt_key' => false, ); $dn = array( "countryName" => $this->enrollment['countryName'], "stateOrProvinceName" => $this->enrollment['stateOrProvinceName'], "localityName" => $this->enrollment['localityName'], "organizationName" => $this->enrollment['organizationName'], "organizationalUnitName" => $this->enrollment['organizationalUnitName'], "commonName" => $sip_address, "emailAddress" => $email ); $this->key = openssl_pkey_new($config); $this->csr = openssl_csr_new($dn, $this->key); openssl_csr_export($this->csr, $this->csr_out); openssl_pkey_export($this->key, $this->key_out, $password, $config); $ca="file://".$this->enrollment['ca_crt']; $this->crt = openssl_csr_sign($this->csr, $ca, $this->enrollment['ca_key'], 3650, $config); if ($this->crt==FALSE) { while (($e = openssl_error_string()) !== false) { echo $e . "\n"; print "

    "; } return false; } openssl_x509_export ($this->crt, $this->crt_out); openssl_pkcs12_export ($this->crt, $this->pk12_out, $this->key, $password); return array( 'crt' => $this->crt_out, 'key' => $this->key_out, 'pk12' => $this->pk12_out, 'ca' => file_get_contents($this->enrollment['ca_crt']) ); } function checkEmail($email) { dprint ("checkEmail($email)"); $regexp = "/^([a-z0-9][a-z0-9_.-]*)@([a-z0-9][a-z0-9-]*\.)+([a-z]{2,})$/i"; if (stristr($email,"-.") || !preg_match($regexp, $email)) { return false; } return true; } function loadTimezones () { if (!$fp = fopen("timezones", "r")) { syslog(LOG_NOTICE, 'Error: Failed to open timezones file'); return false; } while ($buffer = fgets($fp,1024)) { $this->timezones[]=trim($buffer); } fclose($fp); } } class PaypalProcessor { var $deny_countries = array(); var $allow_countries = array(); var $deny_ips = array(); var $make_credit_checks = true; var $transaction_results = array('success' => false); var $vat = 0; function PaypalProcessor($account) { require('cc_processor.php'); $this->CardProcessor = new CreditCardProcessor(); $this->account = &$account; } function refundTransaction($transaction_id) { } function doDirectPayment($basket) { if (!is_object($this->account)) { print " "; print 'Invalid account data'; print " "; return false; } if (!is_array($basket)) { print " "; print 'Invalid basket data'; print " "; return false; } if (is_array($this->test_credit_cards) && in_array($_POST['creditCardNumber'], $this->test_credit_cards)) { $this->CardProcessor->environment='sandbox'; } $this->CardProcessor->chapter_class = 'chapter'; $this->CardProcessor->odd_row_class = 'oddc'; $this->CardProcessor->even_row_class = 'evenc'; $this->CardProcessor->note = $this->account->account; $this->CardProcessor->account = $this->account->account; $this->CardProcessor->vat = $this->vat; // set hidden elements we need to preserve in the shopping cart application $this->CardProcessor->hidden_elements = $this->account->hiddenElements; // load shopping items $this->CardProcessor->cart_items=$basket; // load user information from owner information if available otherwise from sip account settings if ($this->account->owner_information['firstName']) { $this->CardProcessor->user_account['FirstName']=$this->account->owner_information['firstName']; } else { $this->CardProcessor->user_account['FirstName']=$this->account->firstName; } if ($this->account->owner_information['lastName']) { $this->CardProcessor->user_account['LastName']=$this->account->owner_information['lastName']; } else { $this->CardProcessor->user_account['LastName']=$this->account->lastName; } if ($this->account->owner_information['email']) { $this->CardProcessor->user_account['Email']=$this->account->owner_information['email']; } else { $this->CardProcessor->user_account['Email']=$this->account->email; } if ($this->account->owner_information['address'] && $this->account->owner_information['address']!= 'Unknown') { $this->CardProcessor->user_account['Address1']=$this->account->owner_information['address']; } else { $this->CardProcessor->user_account['Address1']=''; } if ($this->account->owner_information['city'] && $this->account->owner_information['city']!= 'Unknown') { $this->CardProcessor->user_account['City']=$this->account->owner_information['city']; } else { $this->CardProcessor->user_account['City']=''; } if ($this->account->owner_information['country'] && $this->account->owner_information['country']!= 'Unknown') { $this->CardProcessor->user_account['Country']=$this->account->owner_information['country']; } else { $this->CardProcessor->user_account['Country']=''; } if ($this->account->owner_information['state'] && $this->account->owner_information['state']!= 'Unknown') { $this->CardProcessor->user_account['State']=$this->account->owner_information['state']; } else { $this->CardProcessor->user_account['State']=''; } if ($this->account->owner_information['postcode'] && $this->account->owner_information['postcode']!= 'Unknown') { $this->CardProcessor->user_account['PostCode']=$this->account->owner_information['postcode']; } else { $this->CardProcessor->user_account['PostCode']=''; } if ($_REQUEST['purchase'] == '1' ) { $chapter=sprintf(_("Transaction Results")); $this->account->showChapter($chapter); print " "; // ensure that submit requests are coming only from the current page if ($_SERVER['HTTP_REFERER'] == $this->CardProcessor->getPageURL()) { // check submitted values $errors = $this->CardProcessor->checkForm($_POST); if (count($errors) > 0){ print $this->CardProcessor->displayFormErrors($errors); foreach (array_keys($errors) as $key) { $log_text.=sprintf("%s:%s ",$errors[$key]['field'],$errors[$key]['desc']); } $log=sprintf("CC transaction for %s failed with error: %s",$this->account->account,$log_text); syslog(LOG_NOTICE, $log); return false; } // process the payment $b=time(); $pay_process_results = $this->CardProcessor->processPayment($_POST); if(count($pay_process_results['error']) > 0){ // there was a problem with payment // show error and stop if ($pay_process_results['error']['field'] == 'reload') { print $pay_process_results['error']['desc']; } else { print $this->CardProcessor->displayProcessErrors($pay_process_results['error']); } $e=time(); $d=$e-$b; $log=sprintf("CC transaction for %s failed with error: %s (%s) after %d seconds", $this->account->account, $pay_process_results['error']['short_message'], $pay_process_results['error']['error_code'], $d ); syslog(LOG_NOTICE, $log); return false; } else { $e=time(); $d=$e-$b; $log=sprintf("CC transaction %s for %s completed succesfully in %d seconds", $pay_process_results['success']['desc']->TransactionID, $this->account->account, $d ); syslog(LOG_NOTICE, $log); print "

    "; print _("Transaction completed sucessfully. "); /* if ($this->CardProcessor->environment!='sandbox' && $this->account->first_transaction) { print "

    "; print _("This is your first payment. "); print "

    "; print _("Please allow the time to check the validity of your transaction before activating your Credit. "); print "

    "; print _("You can speed up the validation process by sending a copy of an utility bill (electriciy, gas or TV) that displays your address. "); print "

    "; printf (_("For questions related to your payments or to request a refund please email to %s and mention your transaction id %s. "), $this->account->billing_email, $pay_process_results['success']['desc']->TransactionID ); $this->make_credit_checks=true; } else { print "

    "; print _("You may check your new balance in the Credit tab. "); } */ } if ($this->account->Preferences['ip'] && $_loc=geoip_record_by_name($this->account->Preferences['ip'])) { $enrollment_location=$_loc['country_name'].'/'.$_loc['city']; } else if ($this->account->Preferences['ip'] && $_loc=geoip_country_name_by_name($this->account->Preferences['ip'])) { $enrollment_location=$_loc; } else { $enrollment_location='Unknown'; } if ($_loc=geoip_record_by_name($_SERVER['REMOTE_ADDR'])) { $transaction_location=$_loc['country_name'].'/'.$_loc['city']; } else if ($_loc=geoip_country_name_by_name($_SERVER['REMOTE_ADDR'])) { $transaction_location=$_loc; } else { $transaction_location='Unknown'; } if ($this->account->Preferences['timezone']) { $timezone=$this->account->Preferences['timezone']; } else { $timezone='Unknown'; } $extra_information=array( 'Account Page' => $this->account->admin_url_absolute, 'Account First Name' => $this->account->firstName, 'Account Last Name ' => $this->account->lastName, 'Account Timezone' => $this->account->timezone, 'Enrollment IP' => $this->account->Preferences['ip'], 'Enrollment Location' => $enrollment_location, 'Enrollment Email' => $this->account->Preferences['registration_email'], 'Enrollment Timezone' => $timezone, 'Transaction Location' => $transaction_location ); $result = $this->account->addInvoice($this->CardProcessor); if ($result) { $extra_information['Invoice Page']=sprintf("https://admin.ag-projects.com/admin/invoice.phtml?iId=%d&adminonly=1",$result['invoice']); } if ($this->CardProcessor->saveOrder($_POST,$pay_process_results,$extra_information)) { $this->transaction_results=array('success' => true, 'id' => $this->CardProcessor->transaction_data['TRANSACTION_ID'] ); return true; } else { $log=sprintf("Error: SIP Account %s - CC transaction %s failed to save order",$this->account->account, $this->CardProcessor->transaction_data['TRANSACTION_ID']); syslog(LOG_NOTICE, $log); return false; } } else { print _("Invalid CC Request"); return false; } print " "; } else { print " "; // print the submit form $arr_form_page_objects = $this->CardProcessor->showSubmitForm(); print $arr_form_page_objects['page_body_content']; print " "; } } function fraudDetected() { if (count($this->deny_ips)) { foreach ($this->deny_ips as $_ip) { if ($this->account->Preferences['ip'] && preg_match("/^$_ip/",$this->account->Preferences['ip'])) { $this->fraud_reason=$this->account->Preferences['ip'].' is Blocked'; return true; } if (preg_match("/^$_ip/",$_SERVER['REMOTE_ADDR'])) { $this->fraud_reason=$_SERVER['REMOTE_ADDR'].' is a Blocked'; return true; } } } if (count($this->deny_countries)) { if ($_loc=geoip_record_by_name($this->account->Preferences['ip'])) { if (in_array($_loc['country_name'],$this->deny_countries)) { $this->fraud_reason=$_loc['country_name'].' is Blocked'; return true; } } } if (count($this->allow_countries)) { if ($_loc=geoip_record_by_name($this->account->Preferences['ip'])) { if (!in_array($_loc['country_name'],$this->allow_countries)) { $this->fraud_reason=$_loc['country_name'].' is Not Allowed'; return true; } } } if (count($this->deny_email_domains)) { if (count($this->accept_email_addresses)) { if (in_array($this->account->email,$this->accept_email_addresses)) return false; } list($user,$domain)= explode("@",$this->account->email); foreach ($this->deny_email_domains as $deny_domain) { if ($domain == $deny_domain) { $this->fraud_reason=sprintf ('Domain %s is Not Allowed',$domain); return true; } } } return false; } } class DIDProcessor { function DIDProcessor() { /* http://www.didww.com/support/ API help page: http://open.didww.com */ $this->db = new DB_CDRTool(); require('didww_soap_library.php'); include("/etc/cdrtool/enrollment/config.ini"); if (!$enrollment['did_username'] || !$enrollment['did_key']) { print '

    Error: Missing DID engine credentials'; return false; } if ($enrollment['did_environment'] == 'production') { $this->did_engine = new WebService_DID_World_Wide__DID_World_Wide_Port(); $this->auth_string = sha1($enrollment['did_username'].$enrollment['did_key']); $this->environment='production'; } else { print "

    Testing DID environment

    "; flush(); $this->did_engine = new WebService_DID_World_Wide__DID_World_Wide_Port_Testing(); $this->auth_string = sha1($enrollment['did_username'].$enrollment['did_key'].'sandbox'); $this->environment='testing'; } $this->did_engine->_options['timeout'] = 30; } function getPrefixesFromRemote () { if (!$this->auth_string) return false; $result = $this->did_engine->didww_getdidwwregions($this->auth_string,$country); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

    Error: %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { foreach ($result as $_country) { foreach ($_country->cities as $_city) { $prefix = $_country->country_prefix.$_city->city_prefix; if (!$_city->isavailable) continue; $prefixes[$prefix]=array('country_prefix' => trim($_country->country_prefix), 'country_name' => trim($_country->country_name), 'country_iso' => trim($_country->country_iso), 'city_name' => trim($_city->city_name), 'city_prefix' => trim($_city->city_prefix), 'setup' => $_city->setup, 'monthly' => $_city->monthly ); } } } return $prefixes; } function getPrefixes () { $query=sprintf("select * from ddi_cache where environment = '%s' and DATE_ADD(date, INTERVAL +1 day) > NOW()",addslashes($this->environment)); if (!$this->db->query($query)) return false; if ($this->db->num_rows()) { $this->db->next_record(); $prefixes = json_decode($this->db->f('cache'),true); if (!is_array($prefixes)) { $prefixes = $this->cachePrefixes(); } } else { $prefixes=$this->cachePrefixes(); } return $prefixes; } function cachePrefixes() { if ($prefixes = $this->getPrefixesFromRemote()) { $query=sprintf("delete from ddi_cache where environment = '%s'",addslashes($this->environment)); $this->db->query($query); $query=sprintf("insert into ddi_cache (cache,date,environment) values ('%s', NOW(),'%s')",addslashes(json_encode($prefixes)),addslashes($this->environment)); $this->db->query($query); return $prefixes; } else { return false; } } function getResellerInfo() { if (!$this->auth_string) return false; $result = $this->did_engine->didww_getdidwwapidetails($this->auth_string); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

    Error: %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { print "

    ";
                 print_r($result);
                 print "
    "; } } function createOrder($data) { if (!$this->auth_string) return false; print "
    ";
             print_r($data);
             print "
    "; $result = $this->did_engine->didww_ordercreate($this->auth_string, $data['customer_id'], $data['country_iso'], $data['city_prefix'], $data['period'], $data['map_data'], $data['prepaid_funds'], $data['uniq_hash'] ); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

    Error: %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { $query=sprintf ("insert into ddi_numbers ( `customer_id`, `country_name`, `city_name`, `did_number`, `did_status`, `did_timeleft`, `did_expire_date_gmt`, `order_id`, `order_status`, `sip_address`, `did_setup`, `did_monthly`, `did_period`, `prepaid_balance`, `environment` ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", addslashes($data['customer_id']), addslashes($result->country_name), addslashes($result->city_name), addslashes($result->did_number), addslashes($result->did_status), addslashes($result->did_timeleft), addslashes($result->did_expire_date_gmt), addslashes($result->order_id), addslashes($result->order_status), addslashes($data['map_data']['map_detail']), addslashes($result->did_setup), addslashes($result->did_monthly), addslashes($result->did_period), addslashes($result->prepaid_balance), addslashes($this->environment) ); if (!$this->db->query($query)) { $log=sprintf ("Database error for DID createOrder: %s (%s)",$this->db->Error,$this->db->Errno); print $log; syslog(LOG_NOTICE, $log); } } } function renewOrder($data) { if (!$this->auth_string) return false; print "

    ";
             print_r($data);
             print "
    "; $result = $this->did_engine->didww_orderautorenew($this->auth_string, $data['customer_id'], $data['number'], $data['period'], $data['uniq_hash'] ); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

    Error: %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { $query=sprintf ("update ddi_numbers set did_timeleft = '%s' and did_expire_date_gmt = '%s' where did_number = '%s' ", addslashes($result->did_timeleft), addslashes($result->did_expire_date_gmt), addslashes($result->did_number) ); if (!$this->db->query($query)) { $log=sprintf ("Database error for DID renewOrder: %s (%s)",$this->db->Error,$this->db->Errno); print $log; syslog(LOG_NOTICE, $log); } print $query; } } function cancelOrder($data) { if (!$this->auth_string) return false; print "

    ";
             print_r($data);
             print "
    "; $result = $this->did_engine->didww_ordercancel($this->auth_string, $data['customer_id'], $data['number'] ); if ((new PEAR)->isError($result)) { $error_msg = $result->getMessage(); $error_fault= $result->getFault(); $error_code = $result->getCode(); printf ("

    Error: %s (%s): %s",$error_msg, $error_fault->detail->exception->errorcode,$error_fault->detail->exception->errorstring); return false; } else { $query=sprintf ("delete from ddi_numbers where did_number = '%s'",addslashes($result->did_number)); if (!$this->db->query($query)) { $log=sprintf ("Database error for DID cancelOrder: %s (%s)",$this->db->Error,$this->db->Errno); print $log; syslog(LOG_NOTICE, $log); } print $query; } } function getOrders($sip_address) { $orders=array(); $query=sprintf ("select * from ddi_numbers where sip_address = '%s' and environment = '%s'",addslashes($sip_address),addslashes($this->environment)); if (!$this->db->query($query)) { $log=sprintf ("Database error for DID createOrder: %s (%s)",$this->db->Error,$this->db->Errno); print $log; syslog(LOG_NOTICE, $log); } else { while ($this->db->next_record()) { $orders[$this->db->f('did_number')]=array('country_name' => $this->db->f('country_name'), 'city_name' => $this->db->f('city_name'), 'did_status' => $this->db->f('did_status'), 'did_timeleft' => $this->db->f('did_timeleft'), 'did_expire_date_gmt' => $this->db->f('did_expire_date_gmt'), 'order_id' => $this->db->f('order_id'), 'order_status' => $this->db->f('order_status'), 'sip_address' => $this->db->f('sip_address'), 'did_setup' => $this->db->f('did_setup'), 'did_monthly' => $this->db->f('did_monthly') ); } } return $orders; } } function RandomIdentifier($length = 30) { $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, strlen($characters) - 1)]; } return $randomString; } function getDisplayNameFromFromHeader($header) { // match all words and whitespace, will be terminated by '<' $name = preg_match("/([\w\s]+).*<.*/", $header, $matches); if (isset($matches[1])) { return trim($matches[1]); } else { return ""; } } if (file_exists("/etc/cdrtool/local/sip_settings.php")) { require_once '/etc/cdrtool/local/sip_settings.php'; } ?>